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? <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 <<a = href=3D"mailto:[email protected]" = class=3D"">[email protected]</a>> 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. <div class=3D""><br = class=3D""></div><div class=3D"">Could the handler ever have its own = stack frame? </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 <<a = href=3D"mailto:[email protected]" = class=3D"">[email protected]</a>> 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:"courier new",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""> ...<br class=3D""> L1():<br = class=3D""> ...<br class=3D""> call L2 (f (x, = y)) handle _ =3D> L3<br class=3D""> L2(n):<br class=3D""> = ...<br class=3D""> raise (m)<br = class=3D""> L3(e):<br class=3D""> ...<br = class=3D""> ...<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`. Just before (the setup of) the call to `f`, the stack = will look something like this:<br class=3D""><br class=3D""> = | tmp3 |<br = class=3D""> | tmp2 = |<br class=3D""> = | tmp1 |<br class=3D""> = | earg: XX |<br class=3D""> = | hand: XX |<br class=3D""> = | link: XX |<br class=3D""> = | arg3 (c) |<br = class=3D""> | arg2 (b) = |<br class=3D"">stackTop -> | arg1 (a) | &1504<br = class=3D"">...<br class=3D"">stackBot -> | ........ | = &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`. 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 <a = href=3D"https://github.com/MLton/mlton/pull/321" = class=3D"">https://github.com/MLton/mlton/pull/321</a>. 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`.<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""> = | arg2 (y) |<br = class=3D"">stackTop -> | arg1 (x) |<br class=3D""> = | L2 |<br = class=3D""> | tmp3 = |<br class=3D""> = | tmp2 |<br class=3D""> = | tmp1 |<br class=3D""> = | earg: XX |<br class=3D""> = | hand: L3 |<br = class=3D""> | link: 1032 |<br = class=3D""> | arg3 (c) = |<br class=3D""> | arg2 (b) = |<br class=3D""> | arg1 = (a) | &1504<br class=3D"">...<br class=3D"">stackBot = -> | .......... | &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` (&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.<br = class=3D""><br class=3D"">Suppose execution continues a bit more, so = that `stackTop` grows yet higher, but no other handlers are = installed. Then the stack will look like:<br class=3D""><br = class=3D"">...<br class=3D""> | = arg2 (j) |<br class=3D"">stackTop -> | arg1 (i) |<br = class=3D"">...<br class=3D""> | = arg2 (y) |<br class=3D""> = | arg1 (x) |<br class=3D""> = | L2 |<br class=3D""> = | tmp3 |<br = class=3D""> | tmp2 = |<br class=3D""> = | tmp1 |<br class=3D""> = | earg: XX |<br class=3D""> = | hand: L3 |<br class=3D""> = | link: 1032 |<br class=3D""> = | arg3 (c) |<br class=3D""> = | arg2 (b) |<br = class=3D""> | arg1 (a) | = &1504<br class=3D"">...<br class=3D"">stackBot -> | = .......... | &288<br class=3D""><br class=3D"">exnStack: = 1256<br class=3D""><br class=3D"">Now, suppose a `raise (v)` = occurs. 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""> | = arg2 (j) |<br class=3D""> = | arg1 (i) |<br class=3D"">...<br class=3D""> = | arg2 (y) |<br class=3D""> = | arg1 (x) |<br = class=3D""> | L2 = |<br class=3D""> = | tmp3 |<br class=3D""> = | tmp2 |<br class=3D""> = | tmp1 |<br = class=3D"">stackTop -> | earg (v) |<br class=3D""> = | hand: L3 |<br = class=3D""> | link: 1032 |<br = class=3D""> | arg3 (c) = |<br class=3D""> | arg2 (b) = |<br class=3D""> | arg1 = (a) | &1504<br class=3D"">...<br class=3D"">stackBot = -> | .......... | &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. (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. 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""> | arg2 (j) = |<br class=3D""> | arg1 (i) = |<br class=3D"">...<br class=3D""> = | arg2 (y) |<br class=3D""> = | arg1 (x) |<br class=3D""> = | L2 |<br = class=3D""> | tmp3 = |<br class=3D""> = | tmp2 |<br class=3D""> = | tmp1 |<br class=3D""> = | earg (v) |<br class=3D""> = | hand: L3 |<br = class=3D""> | link: 1032 |<br = class=3D""> | arg3 (c) = |<br class=3D""> | arg2 (b) = |<br class=3D"">stackTop -> | arg1 (a) | = &1504<br class=3D"">...<br class=3D"">stackBot -> | = .......... | &288<br class=3D""><br class=3D"">exnStack: = 1032<br class=3D""><br class=3D""><br class=3D"">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.</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 = <<a href=3D"mailto:[email protected]" = class=3D"">[email protected]</a>> 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. 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. </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? <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 <<a = href=3D"mailto:[email protected]" target=3D"_blank" = class=3D"">[email protected]</a>> 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:"courier = new",monospace;font-size:large">Your example programs are too = small; all of the `raise <exn>` expressions in them will be turned = into direct jumps to the appropriate handler.</div><div = class=3D"gmail_default" style=3D"font-family:"courier = new",monospace;font-size:large"><br class=3D""></div><div = class=3D"gmail_default" style=3D"font-family:"courier = new",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:"courier= new",monospace;font-size:large"><br class=3D""></div><div = class=3D"gmail_default" style=3D"font-family:"courier = new",monospace;font-size:large">You need a larger program. In = particular, you would want a non-tail recursive function that raises = after growing the stack. For example:</div><div = class=3D"gmail_default" style=3D"font-family:"courier = new",monospace;font-size:large"><br class=3D""></div><div = class=3D"gmail_default" style=3D"font-family:"courier = new",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""> = if i =3D n<br class=3D""> then raise E<br = class=3D""> else if i =3D 0<br class=3D""> = then n<br class=3D""> else 1 + loop(i - 1)<br = class=3D""><br class=3D"">val r =3D loop m handle E =3D> 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>&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:"courier = new",monospace;font-size:large"><br class=3D""></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",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 = <<a href=3D"mailto:[email protected]" target=3D"_blank" = class=3D"">[email protected]</a>> 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 try4.sml<br class=3D""> $ ./try4 2>&1 | grep Raise<br class=3D""> $ ./try4 2>&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> 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 try5.sml<br class=3D""> $ ./try5 2>&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==--