<html>
<head>
<style><!--
.hmmessage P
{
margin:0px;
padding:0px
}
body.hmmessage
{
font-size: 12pt;
font-family:Calibri
}
--></style></head>
<body class='hmmessage'><div dir='ltr'>Any objections? criticisms? suggestions?<div>I'd like to commit this.</div><div><br></div><div>My bootstrapping procedure (boot1.py) precludes cm3 incompatible with m3core/libm3 -- so this is holding up moving to 10.10.4, unless I do some git gyrations.</div><div><br></div><div>Bootstrapping really needs to produce the matching m3core and libm3, so target can have older/newer source.</div><div><br></div><div>Thank you,</div><div> - Jay<br><br><br><div><hr id="stopSpelling">From: jay.krell@cornell.edu<br>To: m3devel@elegosoft.com<br>Subject: alloca(sizeof(jmp_buf)) changes for review<br>Date: Wed, 5 Aug 2015 09:15:22 +0000<br><br>

<style><!--
.ExternalClass .ecxhmmessage P {
padding:0px;
}

.ExternalClass body.ecxhmmessage {
font-size:12pt;
font-family:Calibri;
}

--></style>
<div dir="ltr"><div>Here are my changes for "alloca(sizeof(jmp_buf))".</div><div><br></div><div><br></div><div>NOTE: I updated 3 of the 4 backends, and tested one of them so far.</div><div>I can test the other two.</div><div><br></div><div><br></div><div>NOTE: The update procedure is the same as usual, and very important,</div><div> given the change to M3RT/m3-libs/m3core/src/runtime/ex_frame/RTExFrame.m3.</div><div> The compiler output is closedly tied to m3core.</div><div><br></div><div><br></div><div><br></div><div>NOTE: This uses alloca even for the C backend. I expect to do better later.</div><div><br></div><div><br></div><div>NOTE: The real value here is the deletion of all the target-dependent lines</div><div>in m3-sys/m3middle/src/Target.m3.</div><div><br></div><div><br></div><div>diff --git a/m3-libs/m3core/src/C/Common/Csetjmp.i3 b/m3-libs/m3core/src/C/Common/Csetjmp.i3</div><div>index bd75beb..df2f139 100755</div><div>--- a/m3-libs/m3core/src/C/Common/Csetjmp.i3</div><div>+++ b/m3-libs/m3core/src/C/Common/Csetjmp.i3</div><div>@@ -5,11 +5,22 @@</div><div> UNSAFE INTERFACE Csetjmp;</div><div> FROM Ctypes IMPORT int;</div><div> </div><div>-(* jmp_buf is allocated with alloca(Csetjmp__Jumpbuf_size)</div><div>+(* TODO? Move this to C?</div><div>+</div><div>    "u" in "ulongjmp" is probably for "underscore".</div><div>    This variant of longjmp never restores the signal mask.</div><div>+   Because we believe we never change it?</div><div>+   And restoring it is less efficient? (Requires possible kernel</div><div>+   interaction?)</div><div>+</div><div>+   If the platform only has "regular" longjmp and no signal mask,</div><div>+   e.g. Win32, then this is resolved to that.</div><div>+   </div><div>+   This function does not return in the usual sense.</div><div>+   This is used to raise an exception.</div><div>+   This is subject to be removed, either by using C, or "libunwind", or</div><div>+   Win32 exceptions, or C++ exceptions.</div><div> *)</div><div>-<*EXTERNAL "Csetjmp__Jumpbuf_size" *> VAR Jumpbuf_size: INTEGER;</div><div> <*EXTERNAL "Csetjmp__ulongjmp" *> PROCEDURE ulongjmp (env: ADDRESS; val: int);</div><div> </div><div> END Csetjmp.</div><div>diff --git a/m3-libs/m3core/src/m3core.h b/m3-libs/m3core/src/m3core.h</div><div>index 37a9862..4be9ac3 100644</div><div>--- a/m3-libs/m3core/src/m3core.h</div><div>+++ b/m3-libs/m3core/src/m3core.h</div><div>@@ -358,7 +358,9 @@ extern "C" {</div><div> /* WORD_T/INTEGER are always exactly the same size as a pointer.</div><div>  * VMS sometimes has 32bit size_t/ptrdiff_t but 64bit pointers.</div><div>  */</div><div>-#if defined(_WIN64) || __INITIAL_POINTER_SIZE == 64 || defined(__LP64__) || defined(_LP64)</div><div>+/* commented out is correct, but so is the #else */</div><div>+/*#if defined(_WIN64) || __INITIAL_POINTER_SIZE == 64 || defined(__LP64__) || defined(_LP64)*/</div><div>+#if __INITIAL_POINTER_SIZE == 64</div><div> typedef INT64 INTEGER;</div><div> typedef UINT64 WORD_T;</div><div> #else</div><div>diff --git a/m3-libs/m3core/src/runtime/ex_frame/RTExFrame.m3 b/m3-libs/m3core/src/runtime/ex_frame/RTExFrame.m3</div><div>index 6ec33fc..423a835 100644</div><div>--- a/m3-libs/m3core/src/runtime/ex_frame/RTExFrame.m3</div><div>+++ b/m3-libs/m3core/src/runtime/ex_frame/RTExFrame.m3</div><div>@@ -36,7 +36,7 @@ TYPE (* Except, ExceptElse, Finally *)</div><div>     class     : INTEGER;    (* ORD(ScopeKind) *)</div><div>     handles   : ExceptionList;    (* NIL-terminated list of exceptions handled *)</div><div>     info      : RT0.RaiseActivation;   (* current exception being dispatched *)</div><div>-    jmpbuf    : ARRAY [0..16_FFFF] OF LONGREAL; (* gigantic, size is not used *)</div><div>+    jmpbuf    : ADDRESS; (* allocated with alloca *)</div><div>   END;</div><div> </div><div> TYPE (* FinallyProc *)</div><div>@@ -172,7 +172,7 @@ PROCEDURE InvokeHandler (f: Frame;  READONLY a: RT0.RaiseActivation) RAISES ANY</div><div>     END;</div><div>     RTThread.SetCurrentHandlers (f.next); (* cut to the new handler *)</div><div>     p.info := a;                         (* copy the exception to the new frame *)</div><div>-    Csetjmp.ulongjmp (ADR(p.jmpbuf), 1); (* and jump... *)</div><div>+    Csetjmp.ulongjmp (p.jmpbuf, 1);      (* and jump... *)</div><div>     RAISE OUCH;</div><div>   END InvokeHandler;</div><div> </div><div>diff --git a/m3-libs/m3core/src/unix/Common/Uconstants.c b/m3-libs/m3core/src/unix/Common/Uconstants.c</div><div>index 99b1adf..84095c1 100644</div><div>--- a/m3-libs/m3core/src/unix/Common/Uconstants.c</div><div>+++ b/m3-libs/m3core/src/unix/Common/Uconstants.c</div><div>@@ -46,7 +46,7 @@ typedef int CheckMax[248 - sizeof(CheckMax_t)];</div><div> #include "UerrorX.h"</div><div> </div><div> /* This needs to be aligned to 16, at least for Win32. */</div><div>-EXTERN_CONST INTEGER Csetjmp__Jumpbuf_size = ((sizeof(jmp_buf) + 15) & ~15);</div><div>+EXTERN_CONST INTEGER m3_jmpbuf_size = ((sizeof(jmp_buf) + 15) & ~15);</div><div> </div><div> #ifndef _WIN32</div><div> </div><div>diff --git a/m3-sys/cminstall/src/config-no-install/Darwin.common b/m3-sys/cminstall/src/config-no-install/Darwin.common</div><div>index 0bf3e7e..7043383 100644</div><div><span style="font-size:12pt;"> </span><span style="font-size:12pt;">diff --git a/m3-sys/m3back/src/M3C.m3 b/m3-sys/m3back/src/M3C.m3</span></div><div>index 82285e9..ab858b0 100644</div><div>--- a/m3-sys/m3back/src/M3C.m3</div><div>+++ b/m3-sys/m3back/src/M3C.m3</div><div>@@ -66,7 +66,7 @@ T = M3CG_DoNothing.T BRANDED "M3C.T" OBJECT</div><div>         Err    : ErrorHandler := DefaultErrorHandler;</div><div>         anonymousCounter := -1;</div><div>         c      : Wr.T := NIL;</div><div>-        debug := 0; (* or 0, 1, 2, 3, 4 *)</div><div>+        debug := 1; (* 1-4 *)</div><div>         stack  : RefSeq.T := NIL;</div><div>         params : TextSeq.T := NIL;</div><div>         op_index := 0;</div><div>@@ -80,6 +80,10 @@ T = M3CG_DoNothing.T BRANDED "M3C.T" OBJECT</div><div>         RTHooks_Raise_id: M3ID.T := 0;</div><div>         RTHooks_ReportFault_id: M3ID.T := 0;</div><div>         RTHooks_ReportFault_imported_or_declared := FALSE;</div><div>+        alloca_id : M3ID.T := 0;</div><div>+        setjmp_id : M3ID.T := 0;</div><div>+        u_setjmp_id : M3ID.T := 0;</div><div>+        longjmp_id : M3ID.T := 0;</div><div> </div><div>         (* labels *)</div><div>         labels_min := FIRST(Label);</div><div>@@ -1679,6 +1683,7 @@ TYPE Proc_t = M3CG.Proc OBJECT</div><div>     uplevels := FALSE;</div><div>     is_exception_handler := FALSE;</div><div>     is_RTHooks_Raise := FALSE;</div><div>+    omit_prototype := FALSE;</div><div>     is_RTException_Raise := FALSE;</div><div>     no_return := FALSE;</div><div>     exit_proc_skipped := 0;</div><div>@@ -1752,23 +1757,45 @@ BEGIN</div><div> END IsNameExceptionHandler;</div><div> </div><div> PROCEDURE Proc_Init(proc: Proc_t; self: T): Proc_t =</div><div>-VAR is_common := (proc.parent = NIL</div><div>-                  AND (proc.exported = TRUE OR proc.imported = TRUE)</div><div>-                  AND proc.level = 0</div><div>-                  AND proc.return_type = CGType.Void);</div><div>-    is_RTHooks_ReportFault := (is_common</div><div>-                               AND proc.name = self.RTHooks_ReportFault_id</div><div>-                               AND proc.parameter_count = 2);</div><div>-    is_RTHooks_AssertFailed := (is_common</div><div>-                                AND proc.name = self.RTHooks_AssertFailed_id</div><div>-                                AND proc.parameter_count = 3);</div><div>-BEGIN</div><div>-    proc.is_RTHooks_Raise := (is_common</div><div>-                              AND proc.name = self.RTHooks_Raise_id</div><div>-                              AND proc.parameter_count = 4);</div><div>-    proc.is_RTException_Raise := (is_common</div><div>-                                  AND proc.name = self.RTException_Raise_id</div><div>-                                  AND proc.parameter_count = 1);</div><div>+VAR name := proc.name;</div><div>+    parameter_count := proc.parameter_count;</div><div>+    is_common := proc.parent = NIL</div><div>+                 AND (proc.exported = TRUE OR proc.imported = TRUE)</div><div>+                 AND proc.level = 0;</div><div>+    is_common_void := is_common AND proc.return_type = CGType.Void;</div><div>+    is_RTHooks_ReportFault := is_common_void</div><div>+                              AND name = self.RTHooks_ReportFault_id</div><div>+                              AND parameter_count = 2;</div><div>+    is_RTHooks_AssertFailed := is_common_void</div><div>+                               AND name = self.RTHooks_AssertFailed_id</div><div>+                               AND parameter_count = 3;</div><div>+BEGIN</div><div>+    (* Omit a few prototypes that the frontend might have slightly wrong,</div><div>+       e.g. alloca(unsigned int vs. unsigned long vs. unsigned long long)</div><div>+       vs. not a function.</div><div>+       e.g. setjmp(void* ) vs. setjmp(array)</div><div>+    *)</div><div>+    proc.omit_prototype := is_common</div><div>+                           AND parameter_count = 1 (* TODO 2 for longjmp *)</div><div>+                           AND (name = self.alloca_id</div><div>+                           (* TODO</div><div>+                           - add CGType.Jmpbuf</div><div>+                           - #include <setjmp.h> if there are any</div><div>+                             calls to setjmp/_setjmp/longjmp</div><div>+                             or instances of CGType.Jmpbuf</div><div>+                           - render CGType.Jmpbuf as "jmp_buf"</div><div>+                           - omit setjmp/_setjmp/longjmp prototypes</div><div>+                             OR name = self.setjmp_id</div><div>+                             OR name = self.u_setjmp_id</div><div>+                             OR name = self.longjmp_id</div><div>+                             *)</div><div>+                             );</div><div>+    proc.is_RTHooks_Raise := is_common_void</div><div>+                             AND name = self.RTHooks_Raise_id</div><div>+                             AND parameter_count = 4;</div><div>+    proc.is_RTException_Raise := is_common_void</div><div>+                                 AND name = self.RTException_Raise_id</div><div>+                                 AND parameter_count = 1;</div><div>     IF is_RTHooks_ReportFault THEN</div><div>         self.RTHooks_ReportFault_imported_or_declared := TRUE;</div><div>     END;</div><div>@@ -1777,9 +1804,10 @@ BEGIN</div><div>         no_return(self);</div><div>     END;</div><div>     proc.self := self;</div><div>-    proc.name := Proc_FixName(proc.self, proc.name);</div><div>-    proc.is_exception_handler := proc.level > 0 AND proc.parameter_count = 1 AND IsNameExceptionHandler(self, NameT(proc.name));</div><div>-    proc.parameter_count_without_static_link := proc.parameter_count;</div><div>+    proc.name := Proc_FixName(proc.self, name);</div><div>+    name := proc.name;</div><div>+    proc.is_exception_handler := proc.level > 0 AND parameter_count = 1 AND IsNameExceptionHandler(self, NameT(name));</div><div>+    proc.parameter_count_without_static_link := parameter_count;</div><div>     proc.add_static_link := proc.level > 0;</div><div>     INC(proc.parameter_count, ORD(proc.add_static_link));</div><div>     proc.locals := NEW(RefSeq.T).init();</div><div>@@ -1865,8 +1893,10 @@ CONST Prefix = ARRAY OF TEXT {</div><div> "#pragma warning(disable:4255) /* () change to (void) */",</div><div> "#pragma warning(disable:4668) /* #if of undefined symbol */",</div><div> "#endif",</div><div>-"typedef char* ADDRESS;", (* TODO remove this when we finish strong typing *)</div><div>-"typedef char* STRUCT;",  (* TODO remove this when we finish strong typing *)</div><div>+(* TODO ideally these are char* for K&R or ideally absent when strong</div><div>+   typing and setjmp work done *)</div><div>+"typedef char* ADDRESS;",</div><div>+"typedef char* STRUCT;",</div><div> "typedef signed char INT8;",</div><div> "typedef unsigned char UINT8;",</div><div> "typedef short INT16;",</div><div>@@ -1907,6 +1937,8 @@ CONST Prefix = ARRAY OF TEXT {</div><div> "#include <stddef.h>", (* try to remove this, it is slow -- need size_t *)</div><div> "#endif",</div><div> </div><div>+(* "#include <setjmp.h>", TODO do not always #include *)</div><div>+</div><div> "/* http://c.knowcoding.com/view/23699-portable-alloca.html */",</div><div> "/* Find a good version of alloca. */",</div><div> "#ifndef alloca",</div><div>@@ -1946,7 +1978,7 @@ CONST Prefix = ARRAY OF TEXT {</div><div> "#define STRUCT1(n) typedef struct { volatile char a[n]; }     STRUCT(n);", (* TODO prune if not used *)</div><div> "#define STRUCT2(n) typedef struct { volatile short a[n/2]; }  STRUCT(n);", (* TODO prune if not used *)</div><div> "#define STRUCT4(n) typedef struct { volatile int a[n/4]; }    STRUCT(n);", (* TODO prune if not used *)</div><div>-"#define STRUCT8(n) typedef struct { volatile double a[n/8]; } STRUCT(n);", (* TODO prune if not used *)</div><div>+"#define STRUCT8(n) typedef struct { volatile UINT64 a[n/8]; } STRUCT(n);", (* TODO prune if not used *)</div><div> "#ifdef __cplusplus",</div><div> "#define DOTDOTDOT ...",</div><div> "#else",</div><div>@@ -2285,6 +2317,10 @@ BEGIN</div><div>     self.comment("M3_TARGET = ", Target.System_name);</div><div>     self.comment("M3_WORDSIZE = ", IntToDec(Target.Word.size));</div><div>     self.static_link_id := M3ID.Add("_static_link");</div><div>+    self.alloca_id := M3ID.Add("alloca");</div><div>+    self.setjmp_id := M3ID.Add("setjmp");</div><div>+    self.u_setjmp_id := M3ID.Add("_setjmp"); (* "u" is for underscore *)</div><div>+    self.longjmp_id := M3ID.Add("longjmp");</div><div>     self.RTHooks_ReportFault_id := M3ID.Add("RTHooks__ReportFault");</div><div>     self.RTHooks_Raise_id := M3ID.Add("RTHooks__Raise");</div><div>     self.RTException_Raise_id := M3ID.Add("RTException__Raise");</div><div>@@ -3555,6 +3591,7 @@ BEGIN</div><div>     HelperFunctions_helper_with_type_and_array(self, op, type, types, ARRAY OF TEXT{first});</div><div> END HelperFunctions_helper_with_type;</div><div> </div><div>+(* TODO give up and #include <string.h>? *)</div><div> PROCEDURE HelperFunctions_memset(self: HelperFunctions_t) =</div><div> CONST text = "void* __cdecl memset(void*, int, size_t); /* string.h */";</div><div> BEGIN</div><div>@@ -4270,6 +4307,9 @@ VAR params := proc.params;</div><div>     define_kr := NOT ansi AND kind = FunctionPrototype_t.Define;</div><div>     kr_part2 := "";</div><div> BEGIN</div><div>+    IF proc.omit_prototype THEN</div><div>+      RETURN "";</div><div>+    END;</div><div>     IF NUMBER (params^) = 0 THEN</div><div>         text := text & "(void)";</div><div>     ELSIF NOT ansi AND NOT define_kr THEN</div><div>diff --git a/m3-sys/m3back/src/M3x86.m3 b/m3-sys/m3back/src/M3x86.m3</div><div>index 206f9fb..2fff809 100644</div><div>--- a/m3-sys/m3back/src/M3x86.m3</div><div>+++ b/m3-sys/m3back/src/M3x86.m3</div><div>@@ -3283,7 +3283,7 @@ CONST</div><div>     BP { "m3_rotate_right64",3, Type.Word64, Target.STDCALL },</div><div>     BP { "m3_rotate64",      3, Type.Word64, Target.STDCALL },</div><div>     </div><div>-    BP { "m3_alloca",        0, Type.Addr, Target.CDECL, "__chkstk", EAX }</div><div>+    BP { "alloca",           0, Type.Addr, Target.CDECL, "__chkstk", EAX }</div><div>   };</div><div> </div><div> PROCEDURE start_int_proc (u: U;  b: Builtin) =</div><div>diff --git a/m3-sys/m3cc/gcc/gcc/m3cg/parse.c b/m3-sys/m3cc/gcc/gcc/m3cg/parse.c</div><div>index d965c8a..fdbbdf4 100644</div><div>--- a/m3-sys/m3cc/gcc/gcc/m3cg/parse.c</div><div>+++ b/m3-sys/m3cc/gcc/gcc/m3cg/parse.c</div><div>@@ -643,7 +643,7 @@ static GTY (()) tree t_int;</div><div> #define t_void void_type_node</div><div> static GTY (()) tree t_set;</div><div> </div><div>-static tree m3_alloca;</div><div>+static tree alloca_tree;</div><div> </div><div> static const struct { UINT32 type_id; tree* t; } builtin_uids[] = {</div><div>   { UID_INTEGER, &t_int },</div><div>@@ -1914,7 +1914,7 @@ m3_init_decl_processing (void)</div><div>   bits_per_integer_tree = build_int_cst (t_word, BITS_PER_INTEGER);</div><div>   bytes_per_integer_tree = build_int_cst (t_word, BITS_PER_INTEGER / BITS_PER_UNIT);</div><div>   tree stdcall = get_identifier_with_length (CONSTANT_STRING_AND_LENGTH ("stdcall"));</div><div>-  m3_alloca = get_identifier_with_length (CONSTANT_STRING_AND_LENGTH ("m3_alloca"));</div><div>+  alloca_tree = get_identifier_with_length (CONSTANT_STRING_AND_LENGTH ("alloca"));</div><div>   stdcall_list = build_tree_list (stdcall, NULL);</div><div>   t_set = m3_build_pointer_type (t_word);</div><div> </div><div>@@ -3076,7 +3076,7 @@ fix_name (PCSTR name, size_t length, UINT32 type_id)</div><div>   }</div><div>   else if (type_id == NO_UID)</div><div>   {</div><div>-    buf = (PSTR)alloca (sizet_add(length, 1));</div><div>+    buf = (PSTR)alloca (sizet_add (length, 1));</div><div>     buf[0] = 'M';</div><div>     memcpy (&buf[1], name, length);</div><div>     length += 1;</div><div>@@ -3153,7 +3153,8 @@ m3_pop_param (tree type)</div><div> static tree</div><div> m3_convert_function_to_builtin (tree p)</div><div> {</div><div>-  if (DECL_NAME (p) == m3_alloca)</div><div>+  tree name = DECL_NAME (p);</div><div>+  if (name == alloca_tree)</div><div>     p = builtin_decl_explicit (BUILT_IN_ALLOCA);</div><div>   return p;</div><div> }</div><div>diff --git a/m3-sys/m3front/src/misc/M3.i3 b/m3-sys/m3front/src/misc/M3.i3</div><div>index ec7f972..4a3793e 100644</div><div>--- a/m3-sys/m3front/src/misc/M3.i3</div><div>+++ b/m3-sys/m3front/src/misc/M3.i3</div><div>@@ -11,7 +11,7 @@</div><div> </div><div> INTERFACE M3;</div><div> </div><div>-IMPORT M3ID, M3Buf;</div><div>+IMPORT M3ID, M3Buf, Jmpbufs;</div><div> </div><div> TYPE</div><div>   Flag = BITS 1 FOR BOOLEAN;</div><div>@@ -33,6 +33,7 @@ TYPE</div><div>   ExSet     <: Node;       (* == ESet.T  *)</div><div>   ExSetList <: REFANY;     (* == list of ExSet *)</div><div>   EqAssumption <: ADDRESS; (* == Type.Assumption *)</div><div>+  Procedure <: Value;      (* == Procedure.T *)</div><div> </div><div> (*--------------------------------------------------------- type checking ---*)</div><div> </div><div>@@ -41,13 +42,15 @@ TYPE (* the "global state" that is passed around during type checking *)</div><div>     raises_others : BOOLEAN;</div><div>     ok_to_raise   : ExSetList;</div><div>     no_error      : ExSetList;</div><div>+    jmpbufs       := Jmpbufs.CheckState { };</div><div>   END;</div><div> </div><div> CONST</div><div>   OuterCheckState = CheckState {</div><div>     raises_others := FALSE,</div><div>     ok_to_raise   := NIL,</div><div>-    no_error      := NIL</div><div>+    no_error      := NIL,</div><div>+    jmpbufs       := Jmpbufs.CheckState { }</div><div>   };</div><div> </div><div> (*-------------------------------------------------------- fingerprinting ---*)</div><div>diff --git a/m3-sys/m3front/src/misc/Marker.i3 b/m3-sys/m3front/src/misc/Marker.i3</div><div>index db880a0..8d8f044 100644</div><div>--- a/m3-sys/m3front/src/misc/Marker.i3</div><div>+++ b/m3-sys/m3front/src/misc/Marker.i3</div><div>@@ -64,8 +64,9 @@ PROCEDURE PopFrame (frame: CG.Var);</div><div> PROCEDURE SetLock (acquire: BOOLEAN;  var: CG.Var;  offset: INTEGER);</div><div> (* generate the call to acquire or release a mutex *)</div><div> </div><div>-PROCEDURE CaptureState (frame: CG.Var;  handler: CG.Label);</div><div>-(* call 'setjmp' on 'frame's jmpbuf and branch to 'handler' on re-returns. *)</div><div>+PROCEDURE CaptureState (frame: CG.Var;  jmpbuf: CG.Var;  handler: CG.Label);</div><div>+(* frame.jmpbuf = jmpbuf</div><div>+   if (setjmp(jmpbuf)) goto handler *)</div><div> </div><div> PROCEDURE Reset ();</div><div> </div><div>diff --git a/m3-sys/m3front/src/misc/Marker.m3 b/m3-sys/m3front/src/misc/Marker.m3</div><div>index 6512fbb..9421b7c 100644</div><div>--- a/m3-sys/m3front/src/misc/Marker.m3</div><div>+++ b/m3-sys/m3front/src/misc/Marker.m3</div><div>@@ -53,9 +53,6 @@ VAR</div><div>   all_frames   : FramePtr := NIL;</div><div>   n_frames     : INTEGER  := 0;</div><div>   save_depth   : INTEGER  := 0;</div><div>-  setjmp       : CG.Proc  := NIL;</div><div>-  alloca       : CG.Proc  := NIL;</div><div>-  Jumpbuf_size : CG.Var  := NIL;</div><div>   tos          : INTEGER  := 0;</div><div>   stack        : ARRAY [0..50] OF Frame;</div><div> </div><div>@@ -231,68 +228,13 @@ PROCEDURE CallFinallyHandler (info: CG.Var;</div><div>     END;</div><div>   END CallFinallyHandler;</div><div> </div><div>-PROCEDURE CaptureState (frame: CG.Var;  handler: CG.Label) =</div><div>-  CONST Alloca_jmpbuf = FALSE;</div><div>-  VAR new: BOOLEAN;</div><div>-      label_already_allocated: CG.Label;</div><div>-  BEGIN</div><div>-    (* int setjmp(void* ); *)</div><div>-    IF setjmp = NIL THEN</div><div>-      setjmp := CG.Import_procedure (M3ID.Add (Target.Setjmp), 1,</div><div>-                                     Target.Integer.cg_type,</div><div>-                                     Target.DefaultCall, new);</div><div>-      IF (new) THEN</div><div>-        EVAL CG.Declare_param (M3ID.Add ("jmpbuf"), Target.Address.size,</div><div>-                               Target.Address.align, CG.Type.Addr, 0,</div><div>-                               in_memory := FALSE, up_level := FALSE,</div><div>-                               f := CG.Never);</div><div>-      END;</div><div>-    END;</div><div>-    </div><div>-    IF Alloca_jmpbuf THEN</div><div>-      label_already_allocated := CG.Next_label ();</div><div>-</div><div>-      (* void* _alloca(size_t); *)</div><div>-      IF alloca = NIL THEN</div><div>-        alloca := CG.Import_procedure (M3ID.Add ("m3_alloca"), 1, CG.Type.Addr,</div><div>-                                       Target.DefaultCall, new);</div><div>-        IF new THEN</div><div>-          EVAL CG.Declare_param (M3ID.NoID, Target.Word.size, Target.Word.align,</div><div>-                                 Target.Word.cg_type, 0, in_memory := FALSE,</div><div>-                                 up_level := FALSE, f := CG.Never);</div><div>-        END;</div><div>-      END;</div><div>-      (* extern /*const*/ size_t Csetjmp__Jumpbuf_size/* = sizeof(jmp_buf)*/; *)</div><div>-      IF Jumpbuf_size = NIL THEN</div><div>-        Jumpbuf_size := CG.Import_global (M3ID.Add ("Csetjmp__Jumpbuf_size"),</div><div>-                                          Target.Word.size, Target.Word.align,</div><div>-                                          Target.Word.cg_type, 0);</div><div>-      END;</div><div>-    </div><div>-      (* if (!frame.jmpbuf)</div><div>-           frame.jmpbuf = alloca(Csetjmp__Jumpbuf_size);</div><div>-      *)</div><div>-      CG.Load_addr (frame, M3RT.EF1_jmpbuf);</div><div>-      CG.Load_nil ();</div><div>-      CG.If_compare (Target.Address.cg_type, CG.Cmp.NE, label_already_allocated, CG.Likely);</div><div>-</div><div>-      CG.Start_call_direct (alloca, 0, Target.Address.cg_type);</div><div>-      CG.Load_int (Target.Word.cg_type, Jumpbuf_size);</div><div>-      CG.Pop_param (Target.Word.cg_type);</div><div>-      CG.Call_direct (alloca, Target.Address.cg_type);</div><div>-      CG.Check_nil (CG.RuntimeError.BadMemoryReference);</div><div>-      CG.Store_addr (frame, M3RT.EF1_jmpbuf);</div><div>-</div><div>-      CG.Set_label (label_already_allocated);</div><div>-    END;</div><div>-</div><div>-    (* setjmp(frame.jmpbuf) or setjmp(&frame.jmpbuf) *)</div><div>+PROCEDURE CaptureState (frame: CG.Var;  jmpbuf: CG.Var;  handler: CG.Label) =</div><div>+  VAR setjmp := Module.GetSetjmp (Module.Current ());</div><div>+  BEGIN</div><div>+    CG.Load_addr (jmpbuf);</div><div>+    CG.Store_addr (frame, M3RT.EF1_jmpbuf);</div><div>     CG.Start_call_direct (setjmp, 0, Target.Integer.cg_type);</div><div>-    IF Alloca_jmpbuf THEN</div><div>-      CG.Load_addr (frame, M3RT.EF1_jmpbuf);</div><div>-    ELSE</div><div>-      CG.Load_addr_of (frame, M3RT.EF1_jmpbuf, 128);</div><div>-    END;</div><div>+    CG.Load_addr (jmpbuf);</div><div>     CG.Pop_param (CG.Type.Addr);</div><div>     CG.Call_direct (setjmp, Target.Integer.cg_type);</div><div>     CG.If_true (handler, CG.Never);</div><div>@@ -820,9 +762,6 @@ PROCEDURE Reset () =</div><div>     all_frames   := NIL;</div><div>     n_frames     := 0;</div><div>     save_depth   := 0;</div><div>-    setjmp       := NIL;</div><div>-    alloca       := NIL;</div><div>-    Jumpbuf_size := NIL;</div><div>     tos          := 0;</div><div>   END Reset;</div><div> </div><div>diff --git a/m3-sys/m3front/src/misc/m3makefile b/m3-sys/m3front/src/misc/m3makefile</div><div>index 721cc27..7d5fba3 100644</div><div>--- a/m3-sys/m3front/src/misc/m3makefile</div><div>+++ b/m3-sys/m3front/src/misc/m3makefile</div><div>@@ -16,6 +16,7 @@ module ("M3WString")</div><div> module ("Token")</div><div> module ("Error")</div><div> module ("Host")</div><div>+module ("Jmpbufs")</div><div> module ("Marker")</div><div> module ("Scanner")</div><div> module ("Scope")</div><div>diff --git a/m3-sys/m3front/src/stmts/TryFinStmt.m3 b/m3-sys/m3front/src/stmts/TryFinStmt.m3</div><div>index 89233c5..e0d9b33 100644</div><div>--- a/m3-sys/m3front/src/stmts/TryFinStmt.m3</div><div>+++ b/m3-sys/m3front/src/stmts/TryFinStmt.m3</div><div>@@ -10,6 +10,7 @@ MODULE TryFinStmt;</div><div> </div><div> IMPORT M3ID, CG, Token, Scanner, Stmt, StmtRep, Marker, Target, Type, Addr;</div><div> IMPORT RunTyme, Procedure, ProcBody, M3RT, Scope, Fmt, Host, TryStmt, Module;</div><div>+IMPORT Jmpbufs;</div><div> FROM Stmt IMPORT Outcome;</div><div> </div><div> TYPE</div><div>@@ -20,6 +21,7 @@ TYPE</div><div>         viaProc  : BOOLEAN;</div><div>         scope    : Scope.T;</div><div>         handler  : HandlerProc;</div><div>+        jmpbufs  : Jmpbufs.Try;</div><div>       OVERRIDES</div><div>         check       := Check;</div><div>         compile     := Compile;</div><div>@@ -30,6 +32,7 @@ TYPE</div><div>   HandlerProc = ProcBody.T OBJECT</div><div>     self: P;</div><div>     activation: CG.Var;</div><div>+    jmpbufs : Jmpbufs.Proc;</div><div>   OVERRIDES</div><div>     gen_decl := EmitDecl;</div><div>     gen_body := EmitBody;</div><div>@@ -66,6 +69,7 @@ PROCEDURE Parse (body: Stmt.T;  ): Stmt.T =</div><div> PROCEDURE Check (p: P;  VAR cs: Stmt.CheckState) =</div><div>   VAR zz: Scope.T;  oc: Stmt.Outcomes;  name: INTEGER;</div><div>   BEGIN</div><div>+    Jmpbufs.CheckTry (cs.jmpbufs, p.jmpbufs);</div><div>     Marker.PushFinally (CG.No_label, CG.No_label, NIL);</div><div>     Stmt.TypeCheck (p.body, cs);</div><div>     Marker.Pop ();</div><div>@@ -89,8 +93,11 @@ PROCEDURE Check (p: P;  VAR cs: Stmt.CheckState) =</div><div>           next_uid := 0;</div><div>         END;</div><div>         zz := Scope.Push (p.scope);</div><div>+          p.handler.jmpbufs := Jmpbufs.CheckProcPush (cs.jmpbufs,</div><div>+                                                      M3ID.Add (p.handler.name));</div><div>           Scope.TypeCheck (p.scope, cs);</div><div>           Stmt.TypeCheck (p.finally, cs);</div><div>+          Jmpbufs.CheckProcPop (cs.jmpbufs, p.handler.jmpbufs);</div><div>         Scope.Pop (zz);</div><div>       END;</div><div>     END;</div><div>@@ -226,6 +233,7 @@ PROCEDURE Compile2 (p: P): Stmt.Outcomes =</div><div>     CG.Gen_location (p.forigin);</div><div>     IF (Host.inline_nested_procs) THEN</div><div>       CG.Begin_procedure (p.handler.cg_proc);</div><div>+      Jmpbufs.CompileProcAllocateJmpbufs (p.handler.jmpbufs);</div><div>       xc := Stmt.Compile (p.finally);</div><div>       CG.Exit_proc (CG.Type.Void);</div><div>       CG.End_procedure (p.handler.cg_proc);</div><div>@@ -272,6 +280,7 @@ PROCEDURE EmitBody (x: HandlerProc) =</div><div>       Scanner.offset := p.forigin;</div><div>       CG.Gen_location (p.forigin);</div><div>       CG.Begin_procedure (x.cg_proc);</div><div>+      Jmpbufs.CompileProcAllocateJmpbufs (x.jmpbufs);</div><div>       EVAL Stmt.Compile (p.finally);</div><div>       CG.Exit_proc (CG.Type.Void);</div><div>       CG.End_procedure (x.cg_proc);</div><div>@@ -302,7 +311,7 @@ PROCEDURE Compile3 (p: P): Stmt.Outcomes =</div><div>     l := CG.Next_label (3);</div><div>     CG.Set_label (l, barrier := TRUE);</div><div>     Marker.PushFrame (frame, M3RT.HandlerClass.Finally);</div><div>-    Marker.CaptureState (frame, l+1);</div><div>+    Marker.CaptureState (frame, Jmpbufs.CompileTryGetJmpbuf (p.jmpbufs), l+1);</div><div> </div><div>     (* compile the body *)</div><div>     Marker.PushFinally (l, l+1, frame);</div><div>diff --git a/m3-sys/m3front/src/stmts/TryStmt.m3 b/m3-sys/m3front/src/stmts/TryStmt.m3</div><div>index 8e7a308..a81e0da 100644</div><div>--- a/m3-sys/m3front/src/stmts/TryStmt.m3</div><div>+++ b/m3-sys/m3front/src/stmts/TryStmt.m3</div><div>@@ -10,7 +10,7 @@ MODULE TryStmt;</div><div> </div><div> IMPORT M3, M3ID, CG, Variable, Scope, Exceptionz, Value, Error, Marker;</div><div> IMPORT Type, Stmt, StmtRep, TryFinStmt, Token;</div><div>-IMPORT Scanner, ESet, Target, M3RT, Tracer;</div><div>+IMPORT Scanner, ESet, Target, M3RT, Tracer, Jmpbufs;</div><div> FROM Scanner IMPORT Match, MatchID, GetToken, Fail, cur;</div><div> </div><div> TYPE</div><div>@@ -22,6 +22,7 @@ TYPE</div><div>         hasElse   : BOOLEAN;</div><div>         elseBody  : Stmt.T;</div><div>         handled   : ESet.T;</div><div>+        jmpbufs   : Jmpbufs.Try;</div><div>       OVERRIDES</div><div>         check       := Check;</div><div>         compile     := Compile;</div><div>@@ -162,6 +163,7 @@ PROCEDURE ReverseHandlers (p: P) =</div><div> PROCEDURE Check (p: P;  VAR cs: Stmt.CheckState) =</div><div>   VAR h: Handler;  handled: ESet.T;</div><div>   BEGIN</div><div>+    Jmpbufs.CheckTry (cs.jmpbufs, p.jmpbufs);</div><div>     h := p.handles;</div><div>     WHILE (h # NIL) DO CheckLabels (h, p.scope, cs); h := h.next; END;</div><div> </div><div>@@ -429,7 +431,7 @@ PROCEDURE Compile2 (p: P): Stmt.Outcomes =</div><div>     END;</div><div> </div><div>     (* capture the machine state *)</div><div>-    Marker.CaptureState (frame, l+1);</div><div>+    Marker.CaptureState (frame, Jmpbufs.CompileTryGetJmpbuf (p.jmpbufs), l+1);</div><div> </div><div>     (* compile the body *)</div><div>     oc := Stmt.Compile (p.body);</div><div>diff --git a/m3-sys/m3front/src/values/Module.i3 b/m3-sys/m3front/src/values/Module.i3</div><div>index 58fa9bd..3935126 100644</div><div>--- a/m3-sys/m3front/src/values/Module.i3</div><div>+++ b/m3-sys/m3front/src/values/Module.i3</div><div>@@ -72,4 +72,13 @@ PROCEDURE Reset ();</div><div> PROCEDURE MakeCurrent (t: T);</div><div> (* refresh 't' and its imports for the current compilation *)</div><div> </div><div>+(* Exception handling support, using setjmp/longjmp, w/o front/middle-end</div><div>+   knowing jmpbuf size -- use alloca at runtime getting size from</div><div>+   constant initialized in C; these functions are in Module</div><div>+   to accomodate hypothetical multi-threaded m3front,</div><div>+   i.e. instead of having globals initialized on-demand in Jmpbufs. *)</div><div>+PROCEDURE GetAlloca (t: T) : CG.Proc;</div><div>+PROCEDURE GetJmpbufSize (t: T): CG.Var;</div><div>+PROCEDURE GetSetjmp (t: T) : CG.Proc;</div><div>+</div><div> END Module.</div><div>diff --git a/m3-sys/m3front/src/values/Module.m3 b/m3-sys/m3front/src/values/Module.m3</div><div>index 336b0f2..b587639 100644</div><div>--- a/m3-sys/m3front/src/values/Module.m3</div><div>+++ b/m3-sys/m3front/src/values/Module.m3</div><div>@@ -12,7 +12,7 @@ IMPORT M3, M3ID, CG, Value, ValueRep, Scope, Stmt, Error, ESet,  External;</div><div> IMPORT Variable, Type, Procedure, Ident, M3Buf, BlockStmt, Int;</div><div> IMPORT Host, Token, Revelation, Coverage, Decl, Scanner, WebInfo;</div><div> IMPORT ProcBody, Target, M3RT, Marker, File, Tracer, Wr;</div><div>-IMPORT WCharr; </div><div>+IMPORT WCharr, Jmpbufs; </div><div> </div><div> FROM Scanner IMPORT GetToken, Fail, Match, MatchID, cur;</div><div> </div><div>@@ -50,6 +50,10 @@ REVEAL</div><div>         value_info  : Value.T;</div><div>         lazyAligned : BOOLEAN;</div><div>         containsLazyAlignments: BOOLEAN;</div><div>+        jmpbuf_size  : CG.Var  := NIL;</div><div>+        alloca       : CG.Proc := NIL;</div><div>+        setjmp       : CG.Proc := NIL;</div><div>+        jmpbufs      : Jmpbufs.Proc;</div><div>       OVERRIDES</div><div>         typeCheck   := TypeCheckMethod;</div><div>         set_globals := ValueRep.NoInit;</div><div>@@ -109,6 +113,61 @@ PROCEDURE Reset () =</div><div>     INC (compile_age);</div><div>   END Reset;</div><div> </div><div>+PROCEDURE GetAlloca (t: T) : CG.Proc =</div><div>+VAR new := FALSE;</div><div>+BEGIN</div><div>+   (* alloca must be special cased by backends to mean</div><div>+     alloca, _alloca, chkstk, etc. *)</div><div>+  IF t.alloca = NIL THEN</div><div>+    t.alloca := CG.Import_procedure (M3ID.Add ("alloca"), 1, CG.Type.Addr,</div><div>+                                     Target.DefaultCall, new);</div><div>+    IF new THEN</div><div>+      EVAL CG.Declare_param (M3ID.NoID, Target.Word.size, Target.Word.align,</div><div>+                             Target.Word.cg_type, 0, in_memory := FALSE,</div><div>+                             up_level := FALSE, f := CG.Never);</div><div>+    END;</div><div>+  END;</div><div>+  RETURN t.alloca;</div><div>+END GetAlloca;</div><div>+</div><div>+</div><div>+PROCEDURE GetJmpbufSize (t: T): CG.Var =</div><div>+BEGIN</div><div>+  (* m3_jmpbuf_size is a "constant variable" initialized in </div><div>+     C via:</div><div>+        #include <setjmp.h></div><div>+        extern const m3_jmpbuf_size = sizeof(jmp_buf);</div><div>+     As an optimization, and to avoid any matters involving dynamically</div><div>+     importing data on Win32, Uconstants is always statically linked.</div><div>+     </div><div>+     This isolates the front/middle end from the target.</div><div>+  *)</div><div>+  IF t.jmpbuf_size = NIL THEN</div><div>+    t.jmpbuf_size := CG.Import_global (M3ID.Add ("m3_jmpbuf_size"),</div><div>+                                       Target.Word.size, Target.Word.align,</div><div>+                                       Target.Word.cg_type, 0);</div><div>+  END;</div><div>+  RETURN t.jmpbuf_size;</div><div>+END GetJmpbufSize;</div><div>+</div><div>+PROCEDURE GetSetjmp (t: T): CG.Proc =</div><div>+VAR new := FALSE;</div><div>+BEGIN</div><div>+  (* int setjmp(void* ); *)</div><div>+  IF t.setjmp = NIL THEN</div><div>+    t.setjmp := CG.Import_procedure (M3ID.Add (Target.Setjmp), 1,</div><div>+                                     Target.Integer.cg_type,</div><div>+                                     Target.DefaultCall, new);</div><div>+    IF new THEN</div><div>+      EVAL CG.Declare_param (M3ID.Add ("jmpbuf"), Target.Address.size,</div><div>+                             Target.Address.align, CG.Type.Addr, 0,</div><div>+                             in_memory := FALSE, up_level := FALSE,</div><div>+                             f := CG.Never);</div><div>+    END;</div><div>+  END;</div><div>+  RETURN t.setjmp;</div><div>+END GetSetjmp;</div><div>+</div><div> PROCEDURE Create (name: M3ID.T): T =</div><div>   VAR t: T;</div><div>   BEGIN</div><div>@@ -592,8 +651,10 @@ PROCEDURE TypeCheck (t: T;  main: BOOLEAN;  VAR cs: Value.CheckState) =</div><div>           Revelation.TypeCheck (t.revelations);</div><div>           Scope.TypeCheck (t.localScope, cs);</div><div>           IF (NOT t.interface) THEN</div><div>+            t.jmpbufs := Jmpbufs.CheckProcPush (cs.jmpbufs, 0);</div><div>             BlockStmt.CheckTrace (t.trace, cs);</div><div>             Stmt.TypeCheck (t.block, cs);</div><div>+            Jmpbufs.CheckProcPop (cs.jmpbufs, t.jmpbufs);</div><div>           END;</div><div> </div><div>         ESet.Pop (cs, NIL, t.fails, stop := TRUE);</div><div>@@ -1041,6 +1102,7 @@ PROCEDURE EmitBody (x: InitBody) =</div><div> </div><div>     (* perform the main body *)</div><div>     Tracer.Push (t.trace);</div><div>+    Jmpbufs.CompileProcAllocateJmpbufs (t.jmpbufs);</div><div>     EVAL Stmt.Compile (t.block);</div><div>     Tracer.Pop (t.trace);</div><div> </div><div>diff --git a/m3-sys/m3front/src/values/Procedure.i3 b/m3-sys/m3front/src/values/Procedure.i3</div><div>index dddb1f3..114a3ec 100644</div><div>--- a/m3-sys/m3front/src/values/Procedure.i3</div><div>+++ b/m3-sys/m3front/src/values/Procedure.i3</div><div>@@ -8,9 +8,9 @@</div><div> </div><div> INTERFACE Procedure;</div><div> </div><div>-IMPORT CG, Value, Type, CallExpr, Decl;</div><div>+IMPORT CG, Value, Type, CallExpr, Decl, M3;</div><div> </div><div>-TYPE T <: Value.T;</div><div>+TYPE T = M3.Procedure; (* <: Value.T *)</div><div> </div><div> PROCEDURE ParseDecl (READONLY att: Decl.Attributes;</div><div>                      headerOnly: BOOLEAN := FALSE);</div><div>diff --git a/m3-sys/m3front/src/values/Procedure.m3 b/m3-sys/m3front/src/values/Procedure.m3</div><div>index ad0d39c..39df85b 100644</div><div>--- a/m3-sys/m3front/src/values/Procedure.m3</div><div>+++ b/m3-sys/m3front/src/values/Procedure.m3</div><div>@@ -12,7 +12,7 @@ MODULE Procedure;</div><div> IMPORT M3, M3ID, CG, Value, ValueRep, Type, Scope, Error, Host;</div><div> IMPORT ProcType, Stmt, BlockStmt, Marker, Coverage, M3RT;</div><div> IMPORT CallExpr, Token, Variable, ProcExpr, Tracer;</div><div>-IMPORT Scanner, Decl, ESet, ProcBody, Target, Expr, Formal;</div><div>+IMPORT Scanner, Decl, ESet, ProcBody, Target, Expr, Formal, Jmpbufs;</div><div> FROM Scanner IMPORT GetToken, Match, MatchID, cur;</div><div> </div><div> REVEAL</div><div>@@ -33,6 +33,7 @@ REVEAL</div><div>         cg_proc      : CG.Proc;</div><div>         next_cg_proc : T;</div><div>         end_origin   : INTEGER;</div><div>+        jmpbufs      : Jmpbufs.Proc;</div><div>       OVERRIDES</div><div>         typeCheck   := Check;</div><div>         set_globals := ValueRep.NoInit;</div><div>@@ -307,7 +308,9 @@ PROCEDURE CheckBody (p: T;  VAR cs: Value.CheckState) =</div><div>       INC (Type.recursionDepth);</div><div>         Scope.TypeCheck (p.syms, cs);</div><div>         Marker.PushProcedure (result, p.result, cconv);</div><div>+        p.jmpbufs := Jmpbufs.CheckProcPush (cs.jmpbufs, p.name);</div><div>           Stmt.TypeCheck (p.block, cs);</div><div>+        Jmpbufs.CheckProcPop (cs.jmpbufs, p.jmpbufs);</div><div>         Marker.Pop ();</div><div>         Scope.WarnUnused (p.syms);</div><div>       DEC (Type.recursionDepth);</div><div>@@ -574,6 +577,7 @@ PROCEDURE GenBody (p: T) =</div><div>         Scope.InitValues (p.syms);</div><div>         Scanner.offset := BlockStmt.BodyOffset (p.block);</div><div>         Coverage.CountProcedure (p);</div><div>+        Jmpbufs.CompileProcAllocateJmpbufs (p.jmpbufs);</div><div>         oc := Stmt.Compile (p.block);</div><div>         fallThru := (Stmt.Outcome.FallThrough IN oc);</div><div>       EndRaises (p, l, frame, fallThru);</div><div>diff --git a/m3-sys/m3middle/src/M3RT.m3 b/m3-sys/m3middle/src/M3RT.m3</div><div>index 058cea3..463860c 100644</div><div>--- a/m3-sys/m3middle/src/M3RT.m3</div><div>+++ b/m3-sys/m3middle/src/M3RT.m3</div><div>@@ -10,9 +10,9 @@ IMPORT Target;</div><div> </div><div> PROCEDURE Init () =</div><div>   VAR</div><div>-    IP := Target.Integer.pack;</div><div>-    AP := Target.Address.pack;</div><div>-    CP := Target.Char.pack;</div><div>+    IP := Target.Integer.pack; (* 32 or 64, same as Target.Address.pack *)</div><div>+    AP := Target.Address.pack; (* 32 or 64, same as Target.Integer.pack *)</div><div>+    CP := Target.Char.pack;    (* 8 *)</div><div>   BEGIN</div><div>     (* closure offsets *)</div><div>     CL_marker := 0;                (* : INTEGER *)</div><div>@@ -57,8 +57,8 @@ PROCEDURE Init () =</div><div>     (* Except, ExceptElse, and Finally  frames *)</div><div>     EF1_handles    := EF_SIZE;             (* : ADDRESS *)</div><div>     EF1_info       := EF1_handles + AP;    (* : RTException.Activation *)</div><div>-    EF1_jmpbuf     := RoundUp (EF1_info + EA_SIZE, 128); (* : jmp_buf *)</div><div>-    EF1_SIZE       := EF1_jmpbuf + Target.Jumpbuf_size;</div><div>+    EF1_jmpbuf     := EF1_info + EA_SIZE;  (* : jmp_buf *)</div><div>+    EF1_SIZE       := EF1_jmpbuf + AP;</div><div> </div><div>     (* FinallyProc frames *)</div><div>     EF2_handler    := EF_SIZE;            (* : ADDRESS (PROC) *)</div><div>@@ -149,10 +149,5 @@ PROCEDURE Init () =</div><div>     MUTEX_release := 1 * AP;          (*: PROC() *)</div><div>   END Init;</div><div> </div><div>-PROCEDURE RoundUp (a, b: INTEGER): INTEGER =</div><div>-  BEGIN</div><div>-    RETURN (a + b - 1) DIV b * b;</div><div>-  END RoundUp;</div><div>-</div><div> BEGIN</div><div> END M3RT.</div><div>diff --git a/m3-sys/m3middle/src/Target.i3 b/m3-sys/m3middle/src/Target.i3</div><div>index c0e5c4c..bd27a07 100644</div><div>--- a/m3-sys/m3middle/src/Target.i3</div><div>+++ b/m3-sys/m3middle/src/Target.i3</div><div>@@ -386,9 +386,6 @@ VAR (*CONST*)</div><div>      will cause an address faults.  Hence, no explicit NIL checks are needed</div><div>      for dereferencing with offsets in this range. *)</div><div> </div><div>-  (* Thread stacks *)</div><div>-  Jumpbuf_size     : CARDINAL; (* size of a "jmp_buf" *)</div><div>-</div><div>   (* floating point values *)</div><div>   All_floats_legal : BOOLEAN;</div><div>   (* If all bit patterns are "legal" floating point values (i.e. they can</div><div>diff --git a/m3-sys/m3middle/src/Target.m3 b/m3-sys/m3middle/src/Target.m3</div><div>index 514a75c..475422f 100644</div><div>--- a/m3-sys/m3middle/src/Target.m3</div><div>+++ b/m3-sys/m3middle/src/Target.m3</div><div>@@ -193,132 +193,11 @@ PROCEDURE Init (system: TEXT; in_OS_name: TEXT; backend_mode: M3BackendMode_t):</div><div>     END;</div><div> </div><div>     CASE System OF</div><div>-    </div><div>-    |  Systems.ALPHA_LINUX => Jumpbuf_size := 34 * Address.size;</div><div>-    |  Systems.ALPHA_OPENBSD => Jumpbuf_size := 81 * Address.size;</div><div>-    |  Systems.ALPHA_OSF => Jumpbuf_size := 84 * Address.size;</div><div>-</div><div>-    |  Systems.I386_FREEBSD, Systems.FreeBSD4 =></div><div>-                 Jumpbuf_size              := 11 * Address.size;</div><div>-</div><div>-    |  Systems.AMD64_NETBSD,</div><div>-       Systems.AMD64_OPENBSD,</div><div>-       Systems.AMD64_FREEBSD =></div><div>-                 Jumpbuf_size              := 12 * Address.size;</div><div>-</div><div>-    | Systems.ARM_LINUX,</div><div>-      Systems.ARMEL_LINUX =></div><div>-                 Jumpbuf_size := 64 * Int64.size; (* 392 bytes = 49 * Int64.size on Raspberry Pi *)</div><div>-</div><div>-    |  Systems.PA32_HPUX =></div><div>-                 (* 200 bytes with 8 byte alignment *)</div><div>-                 Jumpbuf_size              := 50 * Address.size;</div><div>-</div><div>-    |  Systems.PA64_HPUX =></div><div>-                 (* 640 bytes with 16 byte alignment *)</div><div>-                 Jumpbuf_size              := 80 * Address.size;</div><div>-</div><div>-    |  Systems.MIPS64_OPENBSD,</div><div>-       Systems.MIPS64EL_OPENBSD =></div><div>-                 Jumpbuf_size              := 16_53 * Address.size;</div><div>-</div><div>-    | Systems.I386_INTERIX =></div><div>-</div><div>-                (* Visual C++'s 16 plus 2 ints: is sigmask saved, its value. *)</div><div>-</div><div>-                Jumpbuf_size := 18 * Address.size;</div><div>-</div><div>-    | Systems.NT386, Systems.I386_NT, Systems.I386_CYGWIN, Systems.I386_MINGW =></div><div>-</div><div>-                 (* Cygwin: 13, Visual C++: 16, Interix: 18.</div><div>-                    Use 18 for interop.</div><div>-                    Cygwin's setjmp.h is wrong by a factor of 4.</div><div>-                    Cygwin provides setjmp and _setjmp that resolve the same.</div><div>-                    Visual C++ provides only _setjmp.</div><div>-                    Visual C++ also has _setjmp3 that the compiler generates</div><div>-                    a call to. In fact _setjmp appears to only use 8 ints</div><div>-                    and _setjmp3 appears to use more. Consider using _setjmp3.</div><div>-                 *)</div><div>-                 Jumpbuf_size := 18 * Address.size;</div><div> </div><div>     | Systems.AMD64_NT =></div><div>-                 (* 256 bytes with 16 byte alignment *)</div><div>-                 Jumpbuf_size := 32 * Int64.size;</div><div>                  Setjmp := "setjmp";</div><div> </div><div>-    | Systems.IA64_FREEBSD, Systems.IA64_HPUX,</div><div>-      Systems.IA64_LINUX, Systems.IA64_NETBSD, Systems.IA64_NT,</div><div>-      Systems.IA64_OPENBSD, Systems.IA64_VMS =></div><div>-                 (* random guess: 1K *)</div><div>-                 Jumpbuf_size     := 128 * Address.size;</div><div>-</div><div>-    | Systems.SPARC32_SOLARIS, Systems.SOLgnu, Systems.SOLsun =></div><div>-                 (* 76 bytes with 4 byte alignment *)</div><div>-                 Jumpbuf_size     := 19 * Address.size;</div><div>-</div><div>-    | Systems.SPARC32_LINUX =></div><div>-                 Jumpbuf_size              := 16_90 * Char.size;</div><div>-</div><div>-    | Systems.SPARC64_OPENBSD =></div><div>-                 Jumpbuf_size := 14 * Address.size;</div><div>-</div><div>-    | Systems.SPARC64_LINUX =></div><div>-                 Jumpbuf_size := 16_280 * Char.size;</div><div>-</div><div>-    | Systems.SPARC64_SOLARIS =></div><div>-                 (* 96 bytes with 8 byte alignment *)</div><div>-                 Jumpbuf_size     := 12 * Address.size;</div><div>-</div><div>-    |  Systems.I386_SOLARIS =></div><div>-                 (* 40 bytes with 4 byte alignment *)</div><div>-                 Jumpbuf_size := 10 * Address.size;</div><div>-</div><div>-    |  Systems.AMD64_SOLARIS =></div><div>-                 (* 64 bytes with 8 byte alignment *)</div><div>-                 Jumpbuf_size := 8 * Address.size;</div><div>-</div><div>-    |  Systems.I386_LINUX, Systems.LINUXLIBC6 =></div><div>-                 Jumpbuf_size              := 39 * Address.size;</div><div>-</div><div>-    |  Systems.AMD64_LINUX =></div><div>-                 Jumpbuf_size              := 25 * Address.size;</div><div>-</div><div>-    |  Systems.I386_DARWIN =></div><div>-                 Jumpbuf_size              := 18 * Address.size;</div><div>-</div><div>-     | Systems.AMD64_DARWIN =></div><div>-                 Jumpbuf_size              := ((9 * 2) + 3 + 16) * Int32.size;</div><div>-</div><div>-    |  Systems.ARM_DARWIN =></div><div>-                 Jumpbuf_size              := 28 * Address.size;</div><div>-</div><div>-    |  Systems.PPC_DARWIN =></div><div>-                 Jumpbuf_size  := 768 * Word8.size;</div><div>-</div><div>-    | Systems.PPC64_DARWIN =></div><div>-                 Jumpbuf_size  := 872 * Word8.size;</div><div>-</div><div>-    |  Systems.PPC_LINUX => </div><div>-                 Jumpbuf_size              := 74 * Int64.size;</div><div>-                 (* ideal alignment is 16 bytes, but 4 is ok *)</div><div>-</div><div>-    |  Systems.PPC32_OPENBSD => </div><div>-                 Jumpbuf_size              := 100 * Address.size;</div><div>-</div><div>-    | Systems.I386_NETBSD =></div><div>-                 Jumpbuf_size              := 14 * Address.size; (* 13? *)</div><div>-                 </div><div>-    | Systems.ALPHA32_VMS,</div><div>-      Systems.ALPHA64_VMS =></div><div>-                 Jumpbuf_size              := 68 * Word64.size;</div><div>-</div><div>-(*  | Systems.I386_MSDOS =></div><div>-                 Jumpbuf_size              := 172 * Char.size; TBD *)</div><div>-</div><div>-    | Systems.I386_OPENBSD =></div><div>-                 Jumpbuf_size              := 10 * Address.size;</div><div>-</div><div>-    ELSE RETURN FALSE;</div><div>+    ELSE</div><div>     END;</div><div> </div><div>     InitCallingConventions (backend_mode,</div><div>diff --git a/m3-sys/m3tests/src/p2/p251/Main.m3 b/m3-sys/m3tests/src/p2/p251/Main.m3</div><div>index 998415e..b6d2d30 100644</div><div>--- a/m3-sys/m3tests/src/p2/p251/Main.m3</div><div>+++ b/m3-sys/m3tests/src/p2/p251/Main.m3</div><div>@@ -172,6 +172,70 @@ BEGIN</div><div>   TRY F6(); EXCEPT END;</div><div> END Main;</div><div> </div><div>+PROCEDURE Finally () =</div><div>+BEGIN</div><div>+  (* same thing but in FINALLY, and nested FINALLY *)</div><div>+  (* NOTE: This testing is haphazard as I don't</div><div>+     understand exception handling enough to aim for coverage. *)</div><div>+  TRY</div><div>+    top_of_stack := GetStack();</div><div>+    F0();</div><div>+  FINALLY</div><div>+    TRY F1(); EXCEPT ELSE Put("exception " & Int(Line())); NL(); END;</div><div>+    TRY F2(); EXCEPT ELSE Put("exception " & Int(Line())); NL(); END;</div><div>+    TRY F3(); EXCEPT ELSE Put("exception " & Int(Line())); NL(); END;</div><div>+    TRY F4(); EXCEPT END;</div><div>+    TRY F5(); EXCEPT END;</div><div>+    TRY F6(); EXCEPT END;</div><div>+  END;</div><div>+END Finally;</div><div>+</div><div>+PROCEDURE NestedFinally() =</div><div>+BEGIN</div><div>+  (* same thing but in FINALLY, and nested FINALLY *)</div><div>+  (* NOTE: This testing is haphazard as I don't</div><div>+     understand exception handling enough to aim for coverage. *)</div><div>+  TRY</div><div>+    top_of_stack := GetStack();</div><div>+    F0();</div><div>+</div><div>+  FINALLY</div><div>+    TRY TRY F1(); FINALLY F0(); END; EXCEPT ELSE Put("exception " & Int(Line())); NL(); END;</div><div>+    TRY TRY F1(); FINALLY F0(); END; EXCEPT ELSE Put("exception " & Int(Line())); NL(); END;</div><div>+    TRY TRY F1(); FINALLY F0(); END; EXCEPT ELSE Put("exception " & Int(Line())); NL(); END; TRY TRY F1(); FINALLY F0(); END; EXCEPT ELSE Put("exception " & Int(Line())); NL(); END;</div><div>+    </div><div>+    TRY</div><div>+      TRY</div><div>+        F2();</div><div>+      EXCEPT</div><div>+      ELSE</div><div>+        Put("exception " & Int(Line())); NL();</div><div>+      END;</div><div>+    FINALLY</div><div>+      F0();</div><div>+    END;    </div><div>+  END;</div><div>+</div><div>+  TRY top_of_stack := GetStack(); TRY F0();</div><div>+  FINALLY TRY F0(); FINALLY F0(); END; END; FINALLY TRY F0(); FINALLY F0(); END; END;</div><div>+ </div><div>+END NestedFinally;</div><div>+</div><div> BEGIN</div><div>   Main();</div><div>+</div><div>+  (* same thing but in Module main *)</div><div>+</div><div>+  top_of_stack := GetStack();</div><div>+  F0();</div><div>+  TRY F1(); EXCEPT ELSE Put("exception " & Int(Line())); NL(); END;</div><div>+  TRY F2(); EXCEPT ELSE Put("exception " & Int(Line())); NL(); END;</div><div>+  TRY F3(); EXCEPT ELSE Put("exception " & Int(Line())); NL(); END;</div><div>+  TRY F4(); EXCEPT END;</div><div>+  TRY F5(); EXCEPT END;</div><div>+  TRY F6(); EXCEPT END;</div><div>+  </div><div>+  Finally();</div><div>+  NestedFinally();</div><div>+</div><div> END Main.</div><div><br></div><div><br></div>ok?<div><br></div><div> - Jay<br><br></div>                                     </div></div></div>                                    </div></body>
</html>