Re: [MLton] understanding exnstack and Raise()
Matthew Fluet <[email protected]> Sat, 20 Jul 2019 20:56:48 -0400
| Newsgroups | gmane.comp.lang.ml.mlton.devel |
|---|---|
| Message-ID | <CAMrhFL4rar42rUn3NjgF-B=-1-stK2O6P_c5mdTive7_bS9+4A@mail.gmail.com> |
--===============2914520558835572370== Content-Type: multipart/alternative; boundary="000000000000cf75dd058e266fca" --000000000000cf75dd058e266fca Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Sat, Jul 20, 2019 at 4:14 PM Jeffrey Murphy <[email protected]> wrote= : > 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? > Yes, all of these steps are just the code for the transfer from the `raise(v)` to the corresponding handler. The actual execution of the handler code is what follows in block L3 of the example. For example, the original SML source code might have been something like: fun g(a, b, c) =3D ... f (x, y) handle e =3D> (* L3: *) ... So, step3 says "transfer control to the handler", but it's much like if we are explaining the low-level execution of a function call, we might have a step that says "transfer control to the function" followed by steps that adjust the stack/frame pointer for the body of the function (i.e., the function prologue). On Jul 20, 2019, at 1:00 PM, Jeffrey Murphy <[email protected]> wrote: > > Thanks for this very helpful post. I have a couple questions regarding > what could happen to stackTop between steps 3 and 4, below. > > Could the handler ever have its own stack frame? > > 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 advan= ce > before step 4 is reached? > > If stackTop can advance, what happens to tmp1, tmp2, tmp3 in that case? > > Thanks! > > On Jun 20, 2019, at 7:11 PM, Matthew Fluet <[email protected]> > wrote: > > In your small examples, the raise expression was "inlined" into the > function that includes the handler; thus, there is no change of frame whe= n > 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` a= nd > 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`, th= e > 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`, tho= se > 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 lab= el > 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 loc= al > 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 th= at > `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 b= elow > 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` 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. > > Suppose execution continues a bit more, so that `stackTop` grows yet > higher, but no other handlers are installed. Then the stack will look li= ke: > > ... > | 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 th= e > 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 sta= ck > 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 reinstall= s > 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 t= o > `exnStack` if it is only going to be immediately overwritten by another > handler installed by `g`. So, we look for opportunities to avoid restori= ng > 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 di= rection >> of Lukasz to make modifications to MLton. I=E2=80=99m working on modifyi= ng 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 h= as >> 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 direc= t >> jump, what is the effect on stackTop? Is that case essentially the same = as >> 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>` expression= s >> 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 debuggin= g >> 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 -ke= ep >> 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 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 the= re 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 >>> 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) >>> >>> >>> >>> 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 >>> ssa -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 >> > _______________________________________________ > 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 > --000000000000cf75dd058e266fca Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div dir=3D"ltr"><div class=3D"gmail_default" style=3D"fon= t-family:courier new,monospace;font-size:large"><span style=3D"font-family:= Arial,Helvetica,sans-serif;font-size:small">On Sat, Jul 20, 2019 at 4:14 PM= Jeffrey Murphy <<a href=3D"mailto:[email protected]">jcmurphy@buffal= o.edu</a>> wrote:</span><br></div></div><div class=3D"gmail_quote"><bloc= kquote 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: b= reak-word;">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?=C2=A0</div></blockquote><div><br></div><div><div c= lass=3D"gmail_default" style=3D"font-family:"courier new",monospa= ce;font-size:large">Yes, all of these steps are just the code for the trans= fer from the `raise(v)` to the corresponding handler.=C2=A0 The actual exec= ution of the handler code is what follows in block L3 of the example.=C2=A0= For example, the original SML source code might have been something like:<= /div><div class=3D"gmail_default" style=3D"font-family:"courier new&qu= ot;,monospace;font-size:large"><br></div><div class=3D"gmail_default" style= =3D"font-family:"courier new",monospace;font-size:large">fun g(a,= b, c) =3D</div><div class=3D"gmail_default" style=3D"font-family:"cou= rier new",monospace;font-size:large">=C2=A0 =C2=A0... f (x, y) handle = e =3D> (* L3: *) ...</div><br></div><div><div class=3D"gmail_default" st= yle=3D"font-family:"courier new",monospace;font-size:large">So, s= tep3 says "transfer control to the handler", but it's much li= ke if we are explaining the low-level execution of a function call, we migh= t have a step that says "transfer control to the function" follow= ed by steps that adjust the stack/frame pointer for the body of the functio= n (i.e., the function prologue).</div><br></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;"><div><div>= <blockquote type=3D"cite"><div>On Jul 20, 2019, at 1:00 PM, Jeffrey Murphy = <<a href=3D"mailto:[email protected]" target=3D"_blank">jcmurphy@buff= alo.edu</a>> wrote:</div><br class=3D"gmail-m_-3714335535766528350Apple-= interchange-newline"><div><div style=3D"overflow-wrap: break-word;">Thanks = for this very helpful post. I have a couple questions regarding what could = happen to stackTop between steps 3 and 4, below.=C2=A0<div><br></div><div>C= ould the handler ever have its own stack frame?=C2=A0</div><div><br></div><= div>Also, what if the handler calls functions that are complex enough to ha= ve their own temporaries, args, and so on, will that cause stackTop to adva= nce before step 4 is reached?</div><div><br></div><div>If stackTop can adva= nce, what happens to tmp1, tmp2, tmp3 in that case?<br><div><br></div><div>= Thanks!</div><div><br><blockquote type=3D"cite"><div>On Jun 20, 2019, at 7:= 11 PM, Matthew Fluet <<a href=3D"mailto:[email protected]" target= =3D"_blank">[email protected]</a>> wrote:</div><br class=3D"gmail-= m_-3714335535766528350Apple-interchange-newline"><div><div dir=3D"ltr"><div= style=3D"font-size:large"><font face=3D"courier new, monospace"></font><sp= an style=3D"font-family:"courier new",monospace;font-size:small">= In your small examples, the raise expression was "inlined" into t= he function that includes the handler; thus, there is no change of frame wh= en the "raise" happens; it's just a simple jump.</span></div>= <font face=3D"courier new, monospace"><br>For an explanation of how excepti= ons adjust stackTop, consider the following fragments of a SSA/SSA2/RSSA fu= nction:<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=A0L3(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`; the function returns normally to block `L2` an= d 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 something 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 |<b= r>stackTop -> | arg1 (a) =C2=A0 | =C2=A0&1504<br>...<br>stackBot -&g= t; | ........ =C2=A0 | =C2=A0 &288<br><br>exnStack: 1032<br><br>`stackT= op` (pointing to address 1504) is actually pointing to the bottom of the fr= ame for `g`.=C2=A0 The arguments of `g` (`a`, `b`, and `c`) are found at th= e bottom of the stack (but, once they are no longer live in `g`, those stac= k slots could be replaced by other locals).=C2=A0 Because `g` installs a ha= ndler (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 h= andler, and `earg` will be the value of the handled exception. =C2=A0(The `= earg` slot is new (as of yesterday); see <a href=3D"https://github.com/MLto= n/mlton/pull/321" target=3D"_blank">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 variables of `g` that must be ke= pt 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 rai= se in L2); by adding `exnStack` to `stackBottom`, one obtains the address o= f the label of the appropriate handler.=C2=A0 Note that `stackBot` + `exnSt= ack` =3D 1320, which is strictly below the stack for `g`.<br><br>Just after= calling `f`, the stack will look something like:<br><br>...<br>=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | arg2 (y) =C2=A0 |<br>stackTop -> | arg= 1 (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&1504<br>...<br>stackBot -> = | .......... | =C2=A0 &288<br><br>exnStack: 1256<br><br>Here's what= has changed: The `exnStack` value (1032) has been stored in the `link` slo= t of `g`'s frame; handler `L3` for this non-tail call has been stored i= n the `hand` slot of `g`'s frame; the address just above the `hand` slo= t of `g`'s frame minus `stackBot` has been stored in `exnStack` (&1= 504 + 8 * 3 (for the arg slots) + 8 (for the link slot) + 8 (for the hand s= lot) - &288 =3D 1256); the continuation label `L2` and the actual argum= ents `x` and `y` have been stored stored at the top of `g`'s frame; `st= ackTop` has been increased to point to the bottom of `f`'s frame.<br><b= r>Suppose execution continues a bit more, so that `stackTop` grows yet high= er, but no other handlers are installed.=C2=A0 Then the stack will look lik= e:<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 |<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 | h= and: 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>= Now, suppose a `raise (v)` occurs.=C2=A0 We "simply" perform the = following:<br><br>1) Write `v` into `*(stackBot + exnStack)` (in the new co= de) or write `v` into a global (in the old code); this communicates the rai= sed value to the handler.<br>2) Set `stackTop` to `stackBot + exnStack`; th= is cuts the stack down so that `stackTop` is just above the appropriate han= dler 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 | l= ink: 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: 12= 56<br><br>3) Jump to `*(stackTop - 8)`; this transfers control to the handl= er. =C2=A0(In the C codegen, this "jump" might need to go through= the trampoline.)<br>4) Subtract 40 from `stackTop`; this cuts the stack do= wn so that it is back at the bottom of `g`'s frame.=C2=A0 The appropria= te amount to cut the stack is known statically and is the `size` of the `fr= ameInfo` for `L3` Handler block.<br>5) Copy the raised value to where L3= 9;s argument variable has been allocated (because the `earg` slot or the gl= obal needs to be available if `g` installs another handler which receives a= raised exception).<br>6) Write the value saved in the `link` slot to `exnS= tack`; this reinstalls the previous exception 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 |<b= r>=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 &288<br><br>exnStack: 1032<br><br><br>This is the genera= l behavior.=C2=A0 There are some additional "optimizations" perfo= rmed by the `implementHandlers` pass.=C2=A0 Note that the "old" a= nd "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 rest= ore the value of the `link` slot to `exnStack` if it is only going to be im= mediately overwritten by another handler installed by `g`.=C2=A0 So, we loo= k for opportunities to avoid restoring and setting `exnStack`.=C2=A0 Simila= rly, 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.</f= ont><br></div><br><br><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"= gmail_attr">On Thu, Jun 20, 2019 at 3:40 PM Jeffrey Murphy <<a href=3D"m= ailto:[email protected]" target=3D"_blank">[email protected]</a>> = wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0= px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><fon= t size=3D"4">Starting with your final question first: I=E2=80=99m woking un= der the direction of Lukasz to make modifications to MLton. I=E2=80=99m wor= king 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 stack= Top.=C2=A0 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 exnSta= ck is used to determine 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 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 ret= urn to the previous stack 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">[email protected]</a>> wrote:</div><br class=3D"gmail-= m_-3714335535766528350gmail-m_1438575144002829419Apple-interchange-newline"= ><div><div dir=3D"ltr"><div style=3D"font-family:"courier new",mo= nospace;font-size:large">Your example programs are too small; all of the `r= aise <exn>` expressions in them will be turned into direct jumps to t= he appropriate handler.</div><div style=3D"font-family:"courier new&qu= ot;,monospace;font-size:large"><br></div><div style=3D"font-family:"co= urier new",monospace;font-size:large">The `Raise()` macros you see in = the generated .c files are from `raise` expressions in the Basis Library im= plementation that correspond to error conditions that are never triggered; = that's why you don't see a debugging message for them.</div><div st= yle=3D"font-family:"courier new",monospace;font-size:large"><br><= /div><div style=3D"font-family:"courier new",monospace;font-size:= large">You need a larger program.=C2=A0 In particular, you would want a non= -tail recursive function that raises after growing the stack.=C2=A0 For exa= mple:</div><div style=3D"font-family:"courier new",monospace;font= -size:large"><br></div><div style=3D"font-family:"courier new",mo= nospace;font-size:large">[mtf@sulfur tmp]$ cat raise-example.sml<br>val n = =3D valOf (Int.fromString (hd (CommandLine.arguments ())))<br>val m =3D val= Of (Int.fromString (hd (tl (CommandLine.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 (concat ["r =3D ", Int.toString r, &quo= t;\n"])<br>[mtf@sulfur tmp]$ ../build/bin/mlton -codegen c -cc-opt = 9;-DDEBUG_CCODEGEN=3DTRUE' -keep g -debug true -expert true -keep ssa -= keep ssa2 -keep rssa -keep machine raise-example.sml<br>[mtf@sulfur tmp]$ .= /raise-example 5 10 2>&1 | grep Raise<br>raise-example.0.c:1445: Rai= se()<br></div><div style=3D"font-family:"courier new",monospace;f= ont-size:large"><br></div><div style=3D"font-family:"courier new"= ,monospace;font-size:large">Is there a specific aspect of the exception han= dling implementation that you'd like to know about?</div><div style=3D"= font-family:"courier new",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 Jeffrey Murphy <<a href=3D"mailto:jcmurph= [email protected]" target=3D"_blank">[email protected]</a>> wrote:<br></d= iv><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bord= er-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> _______________________________________________<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></div></blockquote></div><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></div> --000000000000cf75dd058e266fca-- --===============2914520558835572370== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline --===============2914520558835572370== 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 --===============2914520558835572370==--