mirror of
https://github.com/archlinuxarm/PKGBUILDs.git
synced 2024-11-28 22:57:37 +00:00
269 lines
8.4 KiB
Diff
269 lines
8.4 KiB
Diff
From 798756448180195a6ce020565a5c1d160e491e98 Mon Sep 17 00:00:00 2001
|
|
From: "Erik M. Bray" <erik.bray@lri.fr>
|
|
Date: Thu, 6 Dec 2018 16:11:35 +0000
|
|
Subject: [PATCH 3/3] Prototype for GAP_Enter/Leave macros to bracket use of
|
|
libgap and stack local GAP objects in code which embeds libgap
|
|
|
|
There are two parts to this:
|
|
|
|
First, the outer-most GAP_Enter() must set the StackBottom variable for GASMAN,
|
|
without which objects tracked by GASMAN that are allocated on the stack are
|
|
properly tracked (see #3089).
|
|
|
|
Second, the outer-most GAP_Enter() call should set a jump point for longjmps to
|
|
STATE(ReadJmpError). Code within the GAP kernel may reset this, but we should
|
|
set it here in case any unexpected errors occur within the GAP kernel that are
|
|
not already handled appropriately by a TRY_IF_NO_ERROR.
|
|
|
|
For the first issue, we add GAP_EnterStack() and GAP_LeaveStack() macros which
|
|
implement *just* the StackBottom handling without any other error handling. We
|
|
also add a function to gasman.c called _MarkStackBottomBags which just updates
|
|
the StackBottom variable. Then the macro called MarkStackBottomBags (same name
|
|
without underscore) can be used within a function to set StackBottom to
|
|
somewhere at or near the beginning of that function's stack frame. This uses
|
|
GCC's __builtin_frame_address, but supported is probably needed for other
|
|
platforms that don't have this.
|
|
|
|
The state variable STATE(EnterStackCount) is used to track recursive calls into
|
|
GAP_EnterStack(). We only want to set StackBottom on the outer-most call. The
|
|
count is decremented on GAP_LeaveStack(). Some functions are provided for
|
|
manipulating the counter from the API without directly exposing the GAP state,
|
|
but I'm not sure if this is necessary or desirable, especially since it means
|
|
EnterStackCount isn't updated atomically. My hope was to avoid exposing too
|
|
many GAP internals, but it may be necessary in order to implement these as
|
|
macros.
|
|
|
|
For setting the STATE(ReadJmpError) jump buffer we provide a macro called
|
|
GAP_Error_Setjmp() which is fairly straightforward, except that it needs to be
|
|
written in such a way that it can be used in concert correctly with
|
|
GAP_EnterStack(). In particular, if returning to the site of a
|
|
GAP_Error_Setjmp() call we do not want to accidentally re-increment the
|
|
EnterStackCount.
|
|
|
|
Finally, the higher-level GAP_Enter() and GAP_Leave() macros are provided: The
|
|
latter is just an alias for GAP_LeaveStack(), but the former carefully combines
|
|
*both* GAP_Error_Setjmp() and GAP_EnterStack(). Although called like a
|
|
function, the GAP_Enter() macro expands to a compound statement (necessary for
|
|
both GAP_EnterStack() and GAP_Error_Setjmp() to work properly). The order of
|
|
expansion is also deliberate so that this can be used like:
|
|
|
|
jmp_retval = GAP_Enter();
|
|
|
|
so that the return value of the setjmp call can be stored in a variable while
|
|
using GAP_Enter(), and can be checked to see whether an error occurred.
|
|
However, this requires some care to ensure that the following GAP_EnterStack()
|
|
doesn't increment the EnterStackCount following a return to this point via a
|
|
longjmp.
|
|
|
|
Conflicts:
|
|
src/libgap-api.h
|
|
---
|
|
src/gapstate.h | 3 ++
|
|
src/gasman.c | 6 ++++
|
|
src/gasman.h | 15 ++++++++++
|
|
src/libgap-api.c | 27 +++++++++++++++++
|
|
src/libgap-api.h | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
|
|
5 files changed, 137 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/src/gapstate.h b/src/gapstate.h
|
|
index 72ec4c3..7a2a663 100644
|
|
--- a/src/gapstate.h
|
|
+++ b/src/gapstate.h
|
|
@@ -97,6 +97,9 @@ typedef struct GAPState {
|
|
|
|
UInt1 StateSlots[STATE_SLOTS_SIZE];
|
|
|
|
+ /* For libgap-api.c */
|
|
+ Int EnterStackCount;
|
|
+
|
|
/* Allocation */
|
|
#if !defined(USE_GASMAN)
|
|
#define MAX_GC_PREFIX_DESC 4
|
|
diff --git a/src/gasman.c b/src/gasman.c
|
|
index 13c0b1e..4d2ab3d 100644
|
|
--- a/src/gasman.c
|
|
+++ b/src/gasman.c
|
|
@@ -1193,6 +1193,12 @@ void SetExtraMarkFuncBags(TNumExtraMarkFuncBags func)
|
|
}
|
|
|
|
|
|
+
|
|
+void _MarkStackBottomBags(void* StackBottom) {
|
|
+ StackBottomBags = StackBottom;
|
|
+}
|
|
+
|
|
+
|
|
void InitBags (
|
|
UInt initial_size,
|
|
Bag * stack_bottom,
|
|
diff --git a/src/gasman.h b/src/gasman.h
|
|
index 236eb8b..55e057a 100644
|
|
--- a/src/gasman.h
|
|
+++ b/src/gasman.h
|
|
@@ -982,6 +982,21 @@ extern void InitCollectFuncBags (
|
|
typedef void (*TNumExtraMarkFuncBags)(void);
|
|
extern void SetExtraMarkFuncBags(TNumExtraMarkFuncBags func);
|
|
|
|
+
|
|
+#ifdef __GNUC__
|
|
+#define MarkStackBottomBags() \
|
|
+ _MarkStackBottomBags(__builtin_frame_address(0));
|
|
+/*
|
|
+#else
|
|
+ * TODO: Detect the best stack frame detection technique at configure time
|
|
+ *
|
|
+#define MarkStackBottomBags() \
|
|
+ register void* rbp asm("rbp"); \
|
|
+ _MarkStackBottomBags(rbp);
|
|
+*/
|
|
+#endif
|
|
+extern void _MarkStackBottomBags(void* StackBottom);
|
|
+
|
|
/****************************************************************************
|
|
**
|
|
*F InitBags(...) . . . . . . . . . . . . . . . . . . . . . initialize Gasman
|
|
diff --git a/src/libgap-api.c b/src/libgap-api.c
|
|
index 82cc441..e75b0e2 100644
|
|
--- a/src/libgap-api.c
|
|
+++ b/src/libgap-api.c
|
|
@@ -10,6 +10,8 @@
|
|
#include "lists.h"
|
|
#include "streams.h"
|
|
#include "stringobj.h"
|
|
+#include "system.h"
|
|
+
|
|
|
|
//
|
|
// Setup and initialisation
|
|
@@ -60,3 +62,28 @@ Obj GAP_EvalString(const char * cmd)
|
|
res = READ_ALL_COMMANDS(instream, False, True, viewObjFunc);
|
|
return res;
|
|
}
|
|
+
|
|
+inline syJmp_buf * _GAP_GetReadJmpError(void)
|
|
+{
|
|
+ return &(STATE(ReadJmpError));
|
|
+}
|
|
+
|
|
+inline Int _GAP_GetEnterStackCount(void)
|
|
+{
|
|
+ return STATE(EnterStackCount);
|
|
+}
|
|
+
|
|
+inline void _GAP_IncEnterStackCount(void)
|
|
+{
|
|
+ STATE(EnterStackCount)++;
|
|
+}
|
|
+
|
|
+inline void _GAP_DecEnterStackCount(void)
|
|
+{
|
|
+ STATE(EnterStackCount)--;
|
|
+}
|
|
+
|
|
+inline void _GAP_SetEnterStackCount(Int count)
|
|
+{
|
|
+ STATE(EnterStackCount) = count;
|
|
+}
|
|
diff --git a/src/libgap-api.h b/src/libgap-api.h
|
|
index e45d6fc..55fcd05 100644
|
|
--- a/src/libgap-api.h
|
|
+++ b/src/libgap-api.h
|
|
@@ -5,9 +5,93 @@
|
|
|
|
#include "gap.h"
|
|
|
|
-typedef void (*CallbackFunc)(void);
|
|
+#ifdef __GNUC__
|
|
+#define unlikely(x) __builtin_expect(!!(x), 0)
|
|
+#else
|
|
+#define unlikely(x) (x)
|
|
+#endif
|
|
+
|
|
+
|
|
+#ifndef GAP_ENTER_DEBUG
|
|
+#define GAP_ENTER_DEBUG 0
|
|
+#endif
|
|
+
|
|
+
|
|
+extern syJmp_buf * _GAP_GetReadJmpError(void);
|
|
+extern Int _GAP_GetEnterStackCount(void);
|
|
+extern void _GAP_IncEnterStackCount(void);
|
|
+extern void _GAP_DecEnterStackCount(void);
|
|
+extern void _GAP_SetEnterStackCount(Int count);
|
|
+
|
|
+
|
|
+#if GAP_ENTER_DEBUG
|
|
+#define GAP_ENTER_DEBUG_MESSAGE(message, file, line) \
|
|
+ fprintf(stderr, "%s: %d; %s:%d\n", message, _GAP_EnterStackCount, file, line);
|
|
+#else
|
|
+#define GAP_ENTER_DEBUG_MESSAGE(message, file, line)
|
|
+#endif
|
|
+
|
|
+
|
|
+#define GAP_EnterStack() \
|
|
+ GAP_ENTER_DEBUG_MESSAGE("EnterStack", __FILE__, __LINE__); \
|
|
+ Int _gap_tmp_enter_stack_count = _GAP_GetEnterStackCount(); \
|
|
+ if (_gap_tmp_enter_stack_count < 0) { \
|
|
+ _GAP_SetEnterStackCount(-_gap_tmp_enter_stack_count); \
|
|
+ } else { \
|
|
+ if (_gap_tmp_enter_stack_count == 0) { \
|
|
+ MarkStackBottomBags(); \
|
|
+ } \
|
|
+ _GAP_IncEnterStackCount(); \
|
|
+ }
|
|
+
|
|
|
|
-// Initialisation and finalization
|
|
+#define GAP_LeaveStack() \
|
|
+ _GAP_DecEnterStackCount(); \
|
|
+ GAP_ENTER_DEBUG_MESSAGE("LeaveStack", __FILE__, __LINE__);
|
|
+
|
|
+
|
|
+static inline int _GAP_Error_Prejmp(const char* file, int line) {
|
|
+#if GAP_ENTER_DEBUG
|
|
+ GAP_ENTER_DEBUG_MESSAGE("Error_Prejmp", file, line);
|
|
+#endif
|
|
+ if (_GAP_GetEnterStackCount() > 0) {
|
|
+ return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static inline int _GAP_Error_Postjmp(int JumpRet)
|
|
+{
|
|
+ if (unlikely(JumpRet != 0)) {
|
|
+ /* This only should have been called from the outer-most
|
|
+ * GAP_EnterStack() call so make sure it resets the EnterStackCount; We
|
|
+ * set EnterStackCount to its negative which indicates to
|
|
+ * GAP_EnterStack that we just returned from a long jump and should
|
|
+ * reset EnterStackCount to its value at the return point rather than
|
|
+ * increment it again */
|
|
+ Int tmp_count = _GAP_GetEnterStackCount();
|
|
+ if (tmp_count > 0) {
|
|
+ _GAP_SetEnterStackCount(-tmp_count);
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+#define GAP_Error_Setjmp() (_GAP_Error_Prejmp(__FILE__, __LINE__) || \
|
|
+ _GAP_Error_Postjmp(sySetjmp(*_GAP_GetReadJmpError())))
|
|
+
|
|
+
|
|
+#define GAP_Enter() GAP_Error_Setjmp(); GAP_EnterStack()
|
|
+#define GAP_Leave() GAP_LeaveStack()
|
|
+
|
|
+
|
|
+////
|
|
+//// Setup and initialisation
|
|
+////
|
|
+typedef void (*CallbackFunc)(void);
|
|
|
|
void GAP_Initialize(int argc,
|
|
char ** argv,
|
|
--
|
|
1.9.1
|
|
|