Re: [MLton] understanding exnstack and Raise()

Jeffrey Murphy <[email protected]> Sat, 20 Jul 2019 13:14:33 -0700
Newsgroups gmane.comp.lang.ml.mlton.devel
Message-ID <[email protected]>
--===============5381448234711652573==
Content-Type: multipart/alternative;
	boundary="Apple-Mail=_F567F5E5-6F70-48FC-B4A4-0FE8B3945B55"


--Apple-Mail=_F567F5E5-6F70-48FC-B4A4-0FE8B3945B55
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=utf-8

Perhaps I=E2=80=99m misunderstanding where steps 4-6 occur. Do they =
occur as part of a preamble before the actual (user supplied) code of =
the handler is executed?=20


> On Jul 20, 2019, at 1:00 PM, Jeffrey Murphy <[email protected]> =
wrote:
>=20
> Thanks for this very helpful post. I have a couple questions regarding =
what could happen to stackTop between steps 3 and 4, below.=20
>=20
> Could the handler ever have its own stack frame?=20
>=20
> Also, what if the handler calls functions that are complex enough to =
have their own temporaries, args, and so on, will that cause stackTop to =
advance before step 4 is reached?
>=20
> If stackTop can advance, what happens to tmp1, tmp2, tmp3 in that =
case?
>=20
> Thanks!
>=20
>> On Jun 20, 2019, at 7:11 PM, Matthew Fluet <[email protected] =
<mailto:[email protected]>> wrote:
>>=20
>> 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.
>>=20
>> For an explanation of how exceptions adjust stackTop, consider the =
following fragments of a SSA/SSA2/RSSA function:
>>=20
>> 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):
>>     ...
>>   ...
>>=20
>> 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:
>>=20
>>             | tmp3       |
>>             | tmp2       |
>>             | tmp1       |
>>             | earg: XX   |
>>             | hand: XX   |
>>             | link: XX   |
>>             | arg3 (c)   |
>>             | arg2 (b)   |
>> stackTop -> | arg1 (a)   |  &1504
>> ...
>> stackBot -> | ........   |   &288
>>=20
>> exnStack: 1032
>>=20
>> `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 =
<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 below the stack for `g`.
>>=20
>> Just after calling `f`, the stack will look something like:
>>=20
>> ...
>>             | arg2 (y)   |
>> stackTop -> | arg1 (x)   |
>>             | L2         |
>>             | tmp3       |
>>             | tmp2       |
>>             | tmp1       |
>>             | earg: XX   |
>>             | hand: L3   |
>>             | link: 1032 |
>>             | arg3 (c)   |
>>             | arg2 (b)   |
>>             | arg1 (a)   |  &1504
>> ...
>> stackBot -> | .......... |   &288
>>=20
>> exnStack: 1256
>>=20
>> 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` and `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.
>>=20
>> Suppose execution continues a bit more, so that `stackTop` grows yet =
higher, but no other handlers are installed.  Then the stack will look =
like:
>>=20
>> ...
>>             | 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
>>=20
>> exnStack: 1256
>>=20
>> Now, suppose a `raise (v)` occurs.  We "simply" perform the =
following:
>>=20
>> 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.
>>=20
>> ...
>>             | 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
>>=20
>> exnStack: 1256
>>=20
>> 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.
>>=20
>> ...
>>             | 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
>>=20
>> exnStack: 1032
>>=20
>>=20
>> 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.
>>=20
>>=20
>> On Thu, Jun 20, 2019 at 3:40 PM Jeffrey Murphy <[email protected] =
<mailto:[email protected]>> wrote:
>> 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.  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.=20
>>=20
>> 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 as a return to the previous stack frame?=20
>>=20
>>=20
>>> On Jun 20, 2019, at 1:21 PM, Matthew Fluet <[email protected] =
<mailto:[email protected]>> wrote:
>>>=20
>>> Your example programs are too small; all of the `raise <exn>` =
expressions in them will be turned into direct jumps to the appropriate =
handler.
>>>=20
>>> 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.
>>>=20
>>> You need a larger program.  In particular, you would want a non-tail =
recursive function that raises after growing the stack.  For example:
>>>=20
>>> [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 =
()))))
>>>=20
>>> 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)
>>>=20
>>> val r =3D loop m handle E =3D> 13
>>>=20
>>> 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 =
-keep 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()
>>>=20
>>> Is there a specific aspect of the exception handling implementation =
that you'd like to know about?
>>>=20
>>>=20
>>> On Thu, Jun 20, 2019 at 12:02 PM Jeffrey Murphy =
<[email protected] <mailto:[email protected]>> wrote:
>>> Hi,=20
>>>=20
>>> 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 there doc I can read, or hints anyone can give me?
>>>=20
>>> thanks,
>>> jeff
>>>=20
>>>=20
>>> trival ex 1 (try4.sml)
>>>=20
>>> $ cat try4.sml
>>> exception A
>>> val _ =3D raise A
>>>=20
>>> $ ./build/bin/mlton -codegen c -keep g -debug true -expert true =
-keep ssa -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)
>>>=20
>>>=20
>>>=20
>>> trivial ex 2 (try5.sml)
>>>=20
>>> $ 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
>>>=20
>>> $ ./build/bin/mlton -codegen c -keep g -debug true -expert true =
-keep ssa -keep ssa2 -keep rssa -keep machine  try5.sml
>>> $ ./try5 2>&1 | grep Raise
>>> $
>>>=20
>>> $ git rev-parse --short HEAD
>>> 05004a0
>>> (May 15 commit)
>>>=20
>>>=20
>>>=20
>>>=20
>>> _______________________________________________
>>> MLton-devel mailing list
>>> [email protected] =
<mailto:[email protected]>; [email protected] =
<mailto:[email protected]>
>>> https://lists.sourceforge.net/lists/listinfo/mlton-devel =
<https://lists.sourceforge.net/lists/listinfo/mlton-devel>
>>> _______________________________________________
>>> MLton-devel mailing list
>>> [email protected] =
<mailto:[email protected]>; [email protected] =
<mailto:[email protected]>
>>> https://lists.sourceforge.net/lists/listinfo/mlton-devel =
<https://lists.sourceforge.net/lists/listinfo/mlton-devel>
>>=20
>> _______________________________________________
>> MLton-devel mailing list
>> [email protected] =
<mailto:[email protected]>; [email protected] =
<mailto:[email protected]>
>> https://lists.sourceforge.net/lists/listinfo/mlton-devel =
<https://lists.sourceforge.net/lists/listinfo/mlton-devel>
>> _______________________________________________
>> MLton-devel mailing list
>> [email protected] =
<mailto:[email protected]>; [email protected] =
<mailto:[email protected]>
>> https://lists.sourceforge.net/lists/listinfo/mlton-devel =
<https://lists.sourceforge.net/lists/listinfo/mlton-devel>
>=20


--Apple-Mail=_F567F5E5-6F70-48FC-B4A4-0FE8B3945B55
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html;
	charset=utf-8

<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html; =
charset=3Dutf-8"></head><body style=3D"word-wrap: break-word; =
-webkit-nbsp-mode: space; line-break: after-white-space;" =
class=3D"">Perhaps I=E2=80=99m misunderstanding where steps 4-6 occur. =
Do they occur as part of a preamble before the actual (user supplied) =
code of the handler is executed?&nbsp;<div class=3D""><br =
class=3D""><div><br class=3D""><blockquote type=3D"cite" class=3D""><div =
class=3D"">On Jul 20, 2019, at 1:00 PM, Jeffrey Murphy &lt;<a =
href=3D"mailto:[email protected]" =
class=3D"">[email protected]</a>&gt; wrote:</div><br =
class=3D"Apple-interchange-newline"><div class=3D""><meta =
http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8" =
class=3D""><div style=3D"word-wrap: break-word; -webkit-nbsp-mode: =
space; line-break: after-white-space;" class=3D"">Thanks for this very =
helpful post. I have a couple questions regarding what could happen to =
stackTop between steps 3 and 4, below.&nbsp;<div class=3D""><br =
class=3D""></div><div class=3D"">Could the handler ever have its own =
stack frame?&nbsp;</div><div class=3D""><br class=3D""></div><div =
class=3D"">Also, what if the handler calls functions that are complex =
enough to have their own temporaries, args, and so on, will that cause =
stackTop to advance before step 4 is reached?</div><div class=3D""><br =
class=3D""></div><div class=3D"">If stackTop can advance, what happens =
to tmp1, tmp2, tmp3 in that case?<br class=3D""><div class=3D""><br =
class=3D""></div><div class=3D"">Thanks!</div><div class=3D""><br =
class=3D""><blockquote type=3D"cite" class=3D""><div class=3D"">On Jun =
20, 2019, at 7:11 PM, Matthew Fluet &lt;<a =
href=3D"mailto:[email protected]" =
class=3D"">[email protected]</a>&gt; wrote:</div><br =
class=3D"Apple-interchange-newline"><div class=3D""><div dir=3D"ltr" =
class=3D""><div class=3D"gmail_default" style=3D"font-size:large"><font =
face=3D"courier new, monospace" class=3D""></font><span =
style=3D"font-family:&quot;courier new&quot;,monospace;font-size:small" =
class=3D"">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.</span></div><font face=3D"courier new, monospace" class=3D""><br =
class=3D"">For an explanation of how exceptions adjust stackTop, =
consider the following fragments of a SSA/SSA2/RSSA function:<br =
class=3D""><br class=3D"">fun g(a, b, c) : {returns: (int), raises: =
(exn)} =3D L0()<br class=3D"">&nbsp; ...<br class=3D"">&nbsp; L1():<br =
class=3D"">&nbsp; &nbsp; ...<br class=3D"">&nbsp; &nbsp; call L2 (f (x, =
y)) handle _ =3D&gt; L3<br class=3D"">&nbsp; L2(n):<br class=3D"">&nbsp; =
&nbsp; ...<br class=3D"">&nbsp; &nbsp; raise (m)<br =
class=3D"">&nbsp;L3(e):<br class=3D"">&nbsp; &nbsp; ...<br =
class=3D"">&nbsp; ...<br class=3D""><br class=3D"">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`.&nbsp; Just before (the setup of) the call to `f`, the stack =
will look something like this:<br class=3D""><br class=3D"">&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | tmp3 &nbsp; &nbsp; &nbsp; |<br =
class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | tmp2 &nbsp; =
&nbsp; &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
| tmp1 &nbsp; &nbsp; &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; | earg: XX &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; | hand: XX &nbsp; |<br class=3D"">&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; | link: XX &nbsp; |<br class=3D"">&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg3 (c) &nbsp; |<br =
class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg2 (b) &nbsp; =
|<br class=3D"">stackTop -&gt; | arg1 (a) &nbsp; | &nbsp;&amp;1504<br =
class=3D"">...<br class=3D"">stackBot -&gt; | ........ &nbsp; | &nbsp; =
&amp;288<br class=3D""><br class=3D"">exnStack: 1032<br class=3D""><br =
class=3D"">`stackTop` (pointing to address 1504) is actually pointing to =
the bottom of the frame for `g`.&nbsp; 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).&nbsp; 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. &nbsp;(The `earg` =
slot is new (as of yesterday); see <a =
href=3D"https://github.com/MLton/mlton/pull/321" =
class=3D"">https://github.com/MLton/mlton/pull/321</a>.&nbsp; In the =
version of MLton that you are working with, the value of a handled =
exception is communicated through a global variable.) &nbsp;The `tmp1`, =
`tmp2`, and `tmp3` slots are local variables of `g` that must be kept =
live across the non-tail call of `g`.&nbsp; 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.&nbsp; Note that =
`stackBot` + `exnStack` =3D 1320, which is strictly below the stack for =
`g`.<br class=3D""><br class=3D"">Just after calling `f`, the stack will =
look something like:<br class=3D""><br class=3D"">...<br class=3D"">&nbsp;=
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg2 (y) &nbsp; |<br =
class=3D"">stackTop -&gt; | arg1 (x) &nbsp; |<br class=3D"">&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | L2 &nbsp; &nbsp; &nbsp; &nbsp; |<br =
class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | tmp3 &nbsp; =
&nbsp; &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
| tmp2 &nbsp; &nbsp; &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; | tmp1 &nbsp; &nbsp; &nbsp; |<br class=3D"">&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; | earg: XX &nbsp; |<br class=3D"">&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | hand: L3 &nbsp; |<br =
class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | link: 1032 |<br =
class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg3 (c) &nbsp; =
|<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg2 (b) =
&nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg1 =
(a) &nbsp; | &nbsp;&amp;1504<br class=3D"">...<br class=3D"">stackBot =
-&gt; | .......... | &nbsp; &amp;288<br class=3D""><br =
class=3D"">exnStack: 1256<br class=3D""><br class=3D"">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` (&amp;1504 =
+ 8 * 3 (for the arg slots) + 8 (for the link slot) + 8 (for the hand =
slot) - &amp;288 =3D 1256); the continuation label `L2` and the actual =
arguments `x` and `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.<br =
class=3D""><br class=3D"">Suppose execution continues a bit more, so =
that `stackTop` grows yet higher, but no other handlers are =
installed.&nbsp; Then the stack will look like:<br class=3D""><br =
class=3D"">...<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | =
arg2 (j) &nbsp; |<br class=3D"">stackTop -&gt; | arg1 (i) &nbsp; |<br =
class=3D"">...<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | =
arg2 (y) &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; | arg1 (x) &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; | L2 &nbsp; &nbsp; &nbsp; &nbsp; |<br class=3D"">&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | tmp3 &nbsp; &nbsp; &nbsp; |<br =
class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | tmp2 &nbsp; =
&nbsp; &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
| tmp1 &nbsp; &nbsp; &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; | earg: XX &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; | hand: L3 &nbsp; |<br class=3D"">&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; | link: 1032 |<br class=3D"">&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; | arg3 (c) &nbsp; |<br class=3D"">&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg2 (b) &nbsp; |<br =
class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg1 (a) &nbsp; | =
&nbsp;&amp;1504<br class=3D"">...<br class=3D"">stackBot -&gt; | =
.......... | &nbsp; &amp;288<br class=3D""><br class=3D"">exnStack: =
1256<br class=3D""><br class=3D"">Now, suppose a `raise (v)` =
occurs.&nbsp; We "simply" perform the following:<br class=3D""><br =
class=3D"">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.<br class=3D"">2) Set `stackTop` to =
`stackBot + exnStack`; this cuts the stack down so that `stackTop` is =
just above the appropriate handler label.<br class=3D""><br =
class=3D"">...<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | =
arg2 (j) &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; | arg1 (i) &nbsp; |<br class=3D"">...<br class=3D"">&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; | arg2 (y) &nbsp; |<br class=3D"">&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg1 (x) &nbsp; |<br =
class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | L2 &nbsp; &nbsp; =
&nbsp; &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
| tmp3 &nbsp; &nbsp; &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; | tmp2 &nbsp; &nbsp; &nbsp; |<br class=3D"">&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; | tmp1 &nbsp; &nbsp; &nbsp; |<br =
class=3D"">stackTop -&gt; | earg (v) &nbsp; |<br class=3D"">&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | hand: L3 &nbsp; |<br =
class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | link: 1032 |<br =
class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg3 (c) &nbsp; =
|<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg2 (b) =
&nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg1 =
(a) &nbsp; | &nbsp;&amp;1504<br class=3D"">...<br class=3D"">stackBot =
-&gt; | .......... | &nbsp; &amp;288<br class=3D""><br =
class=3D"">exnStack: 1256<br class=3D""><br class=3D"">3) Jump to =
`*(stackTop - 8)`; this transfers control to the handler. &nbsp;(In the =
C codegen, this "jump" might need to go through the trampoline.)<br =
class=3D"">4) Subtract 40 from `stackTop`; this cuts the stack down so =
that it is back at the bottom of `g`'s frame.&nbsp; The appropriate =
amount to cut the stack is known statically and is the `size` of the =
`frameInfo` for `L3` Handler block.<br class=3D"">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).<br class=3D"">6) Write the =
value saved in the `link` slot to `exnStack`; this reinstalls the =
previous exception handler.<br class=3D""><br class=3D"">...<br =
class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg2 (j) &nbsp; =
|<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg1 (i) =
&nbsp; |<br class=3D"">...<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; | arg2 (y) &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; | arg1 (x) &nbsp; |<br class=3D"">&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; | L2 &nbsp; &nbsp; &nbsp; &nbsp; |<br =
class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | tmp3 &nbsp; =
&nbsp; &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
| tmp2 &nbsp; &nbsp; &nbsp; |<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; | tmp1 &nbsp; &nbsp; &nbsp; |<br class=3D"">&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; | earg (v) &nbsp; |<br class=3D"">&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | hand: L3 &nbsp; |<br =
class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | link: 1032 |<br =
class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg3 (c) &nbsp; =
|<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | arg2 (b) =
&nbsp; |<br class=3D"">stackTop -&gt; | arg1 (a) &nbsp; | =
&nbsp;&amp;1504<br class=3D"">...<br class=3D"">stackBot -&gt; | =
.......... | &nbsp; &amp;288<br class=3D""><br class=3D"">exnStack: =
1032<br class=3D""><br class=3D""><br class=3D"">This is the general =
behavior.&nbsp; There are some additional "optimizations" performed by =
the `implementHandlers` pass.&nbsp; Note that the "old" and "new" =
`exnStack` values are the same for every handler that `g` =
installs.&nbsp; Thus, we only need to copy the "old" `exnStack` to the =
`link` slot once.&nbsp; 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`.&nbsp; So, =
we look for opportunities to avoid restoring and setting =
`exnStack`.&nbsp; 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.</font><br class=3D""></div><br =
class=3D""><br class=3D""><div class=3D"gmail_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]" =
class=3D"">[email protected]</a>&gt; wrote:<br =
class=3D""></div><blockquote class=3D"gmail_quote" style=3D"margin:0px =
0px 0px 0.8ex;border-left:1px solid =
rgb(204,204,204);padding-left:1ex"><div style=3D"overflow-wrap: =
break-word;" class=3D""><font size=3D"4" class=3D"">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.&nbsp; 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.&nbsp;</font><div class=3D""><font size=3D"4" class=3D""><br =
class=3D""></font></div><div class=3D""><font size=3D"4" class=3D"">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 =
as a return to the previous stack frame?&nbsp;<br class=3D""></font><div =
class=3D""><font size=3D"4" class=3D""><br class=3D""></font></div><div =
class=3D""><br class=3D""><blockquote type=3D"cite" class=3D""><div =
class=3D"">On Jun 20, 2019, at 1:21 PM, Matthew Fluet &lt;<a =
href=3D"mailto:[email protected]" target=3D"_blank" =
class=3D"">[email protected]</a>&gt; wrote:</div><br =
class=3D"gmail-m_1438575144002829419Apple-interchange-newline"><div =
class=3D""><div dir=3D"ltr" class=3D""><div class=3D"gmail_default" =
style=3D"font-family:&quot;courier =
new&quot;,monospace;font-size:large">Your example programs are too =
small; all of the `raise &lt;exn&gt;` expressions in them will be turned =
into direct jumps to the appropriate handler.</div><div =
class=3D"gmail_default" style=3D"font-family:&quot;courier =
new&quot;,monospace;font-size:large"><br class=3D""></div><div =
class=3D"gmail_default" style=3D"font-family:&quot;courier =
new&quot;,monospace;font-size:large">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.</div><div class=3D"gmail_default" style=3D"font-family:&quot;courier=
 new&quot;,monospace;font-size:large"><br class=3D""></div><div =
class=3D"gmail_default" style=3D"font-family:&quot;courier =
new&quot;,monospace;font-size:large">You need a larger program.&nbsp; In =
particular, you would want a non-tail recursive function that raises =
after growing the stack.&nbsp; For example:</div><div =
class=3D"gmail_default" style=3D"font-family:&quot;courier =
new&quot;,monospace;font-size:large"><br class=3D""></div><div =
class=3D"gmail_default" style=3D"font-family:&quot;courier =
new&quot;,monospace;font-size:large">[mtf@sulfur tmp]$ cat =
raise-example.sml<br class=3D"">val n =3D valOf (Int.fromString (hd =
(CommandLine.arguments ())))<br class=3D"">val m =3D valOf =
(Int.fromString (hd (tl (CommandLine.arguments ()))))<br class=3D""><br =
class=3D"">exception E<br class=3D"">fun loop i =3D<br class=3D"">&nbsp; =
&nbsp;if i =3D n<br class=3D"">&nbsp; &nbsp; &nbsp; then raise E<br =
class=3D"">&nbsp; &nbsp;else if i =3D 0<br class=3D"">&nbsp; &nbsp; =
&nbsp; then n<br class=3D"">&nbsp; &nbsp;else 1 + loop(i - 1)<br =
class=3D""><br class=3D"">val r =3D loop m handle E =3D&gt; 13<br =
class=3D""><br class=3D"">val _ =3D print (concat ["r =3D ", =
Int.toString r, "\n"])<br class=3D"">[mtf@sulfur tmp]$ =
../build/bin/mlton -codegen c -cc-opt '-DDEBUG_CCODEGEN=3DTRUE' -keep g =
-debug true -expert true -keep ssa -keep ssa2 -keep rssa -keep machine =
raise-example.sml<br class=3D"">[mtf@sulfur tmp]$ ./raise-example 5 10 =
2&gt;&amp;1 | grep Raise<br class=3D"">raise-example.0.c:1445: =
Raise()<br class=3D""></div><div class=3D"gmail_default" =
style=3D"font-family:&quot;courier =
new&quot;,monospace;font-size:large"><br class=3D""></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'd like to know =
about?</div><div class=3D"gmail_default" =
style=3D"font-family:&quot;courier =
new&quot;,monospace;font-size:large"><br class=3D""></div></div><br =
class=3D""><div class=3D"gmail_quote"><div dir=3D"ltr" =
class=3D"gmail_attr">On Thu, Jun 20, 2019 at 12:02 PM Jeffrey Murphy =
&lt;<a href=3D"mailto:[email protected]" target=3D"_blank" =
class=3D"">[email protected]</a>&gt; wrote:<br =
class=3D""></div><blockquote class=3D"gmail_quote" style=3D"margin:0px =
0px 0px 0.8ex;border-left:1px solid =
rgb(204,204,204);padding-left:1ex">Hi, <br class=3D"">
<br class=3D"">
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 =
there doc I can read, or hints anyone can give me?<br class=3D"">
<br class=3D"">
thanks,<br class=3D"">
jeff<br class=3D"">
<br class=3D"">
<br class=3D"">
trival ex 1 (try4.sml)<br class=3D"">
<br class=3D"">
$ cat try4.sml<br class=3D"">
exception A<br class=3D"">
val _ =3D raise A<br class=3D"">
<br class=3D"">
$ ./build/bin/mlton -codegen c -keep g -debug true -expert true -keep =
ssa -keep ssa2 -keep rssa -keep machine&nbsp; try4.sml<br class=3D"">
$ ./try4 2&gt;&amp;1 | grep Raise<br class=3D"">
$ ./try4 2&gt;&amp;1 | tail<br class=3D"">
try4.1.c:216: Push (-12)<br class=3D"">
try4.1.c:225: BNZ(0, L_106)<br class=3D"">
try4.1.c:225: BNZ(1, L_106)<br class=3D"">
try4.1.c:261: BNZ(0, L_35)<br class=3D"">
try4.1.c:261: BNZ(1, L_35)<br class=3D"">
try4.1.c:225: BNZ(1, L_106)<br class=3D"">
try4.1.c:261: BNZ(0, L_35)<br class=3D"">
try4.1.c:261: BNZ(1, L_35)<br class=3D"">
unhandled exception: A<br class=3D"">
try4.1.c:234: BNZ(0, L_26)<br class=3D"">
<br class=3D"">
<br class=3D"">
<br class=3D"">
trivial ex 2 (try5.sml)<br class=3D"">
<br class=3D"">
$ cat try5.sml<br class=3D"">
exception A<br class=3D"">
fun y z =3D raise A<br class=3D"">
fun x z =3D y z handle A =3D&gt; 1<br class=3D"">
val _ =3D x 1<br class=3D"">
<br class=3D"">
$ ./build/bin/mlton -codegen c -keep g -debug true -expert true -keep =
ssa -keep ssa2 -keep rssa -keep machine&nbsp; try5.sml<br class=3D"">
$ ./try5 2&gt;&amp;1 | grep Raise<br class=3D"">
$<br class=3D"">
<br class=3D"">
$ git rev-parse --short HEAD<br class=3D"">
05004a0<br class=3D"">
(May 15 commit)<br class=3D"">
<br class=3D"">
<br class=3D"">
<br class=3D"">
<br class=3D"">
_______________________________________________<br class=3D"">
MLton-devel mailing list<br class=3D"">
<a href=3D"mailto:[email protected]" target=3D"_blank" =
class=3D"">[email protected]</a>; <a =
href=3D"mailto:[email protected]" target=3D"_blank" =
class=3D"">[email protected]</a><br class=3D"">
<a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-devel" =
rel=3D"noreferrer" target=3D"_blank" =
class=3D"">https://lists.sourceforge.net/lists/listinfo/mlton-devel</a><br=
 class=3D"">
</blockquote></div>
_______________________________________________<br class=3D"">MLton-devel =
mailing list<br class=3D""><a =
href=3D"mailto:[email protected]" target=3D"_blank" =
class=3D"">[email protected]</a>; <a =
href=3D"mailto:[email protected]" target=3D"_blank" =
class=3D"">[email protected]</a><br class=3D""><a =
href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-devel" =
target=3D"_blank" =
class=3D"">https://lists.sourceforge.net/lists/listinfo/mlton-devel</a><br=
 class=3D""></div></blockquote></div><br =
class=3D""></div></div>_______________________________________________<br =
class=3D"">
MLton-devel mailing list<br class=3D"">
<a href=3D"mailto:[email protected]" target=3D"_blank" =
class=3D"">[email protected]</a>; <a =
href=3D"mailto:[email protected]" target=3D"_blank" =
class=3D"">[email protected]</a><br class=3D"">
<a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-devel" =
rel=3D"noreferrer" target=3D"_blank" =
class=3D"">https://lists.sourceforge.net/lists/listinfo/mlton-devel</a><br=
 class=3D"">
</blockquote></div>
_______________________________________________<br class=3D"">MLton-devel =
mailing list<br class=3D""><a =
href=3D"mailto:[email protected]" =
class=3D"">[email protected]</a>; <a =
href=3D"mailto:[email protected]" =
class=3D"">[email protected]</a><br class=3D""><a =
href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-devel" =
class=3D"">https://lists.sourceforge.net/lists/listinfo/mlton-devel</a><br=
 class=3D""></div></blockquote></div><br =
class=3D""></div></div></div></blockquote></div><br =
class=3D""></div></body></html>=

--Apple-Mail=_F567F5E5-6F70-48FC-B4A4-0FE8B3945B55--


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


--===============5381448234711652573==
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

--===============5381448234711652573==--