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