[DTrace-devel] [PATCH 07/20] regset: add spill protection
Nick Alcock
nick.alcock at oracle.com
Wed May 11 21:12:49 UTC 2022
This simple mechanism allows callers to prevent specific registers from
being spilled, perhaps while a live variable holding that reg number is
in active use.
Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
---
libdtrace/dt_regset.c | 29 ++++++++++++++++++++++++++---
libdtrace/dt_regset.h | 2 ++
2 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/libdtrace/dt_regset.c b/libdtrace/dt_regset.c
index 6028e389dc1f..37e6166c565f 100644
--- a/libdtrace/dt_regset.c
+++ b/libdtrace/dt_regset.c
@@ -31,9 +31,12 @@ dt_regset_create(ulong_t size, dt_cg_spill_f stf, dt_cg_spill_f ldf)
drp->dr_spill_load = ldf;
drp->dr_active = malloc(BT_SIZEOFMAP(size));
drp->dr_spilled = malloc(BT_SIZEOFMAP(size));
- if (drp->dr_active == NULL || drp->dr_spilled == NULL) {
+ drp->dr_nonspillable = malloc(BT_SIZEOFMAP(size));
+ if (drp->dr_active == NULL || drp->dr_spilled == NULL ||
+ drp->dr_nonspillable == NULL) {
free(drp->dr_active);
free(drp->dr_spilled);
+ free(drp->dr_nonspillable);
free(drp);
return NULL;
}
@@ -47,6 +50,7 @@ dt_regset_destroy(dt_regset_t *drp)
{
free(drp->dr_active);
free(drp->dr_spilled);
+ free(drp->dr_nonspillable);
free(drp);
}
@@ -55,6 +59,7 @@ dt_regset_reset(dt_regset_t *drp)
{
memset(drp->dr_active, 0, BT_SIZEOFMAP(drp->dr_size));
memset(drp->dr_spilled, 0, BT_SIZEOFMAP(drp->dr_size));
+ memset(drp->dr_nonspillable, 0, BT_SIZEOFMAP(drp->dr_size));
}
int
@@ -70,7 +75,8 @@ dt_regset_alloc(dt_regset_t *drp)
}
for (reg = drp->dr_size - 1; reg > 0; reg--) {
- if (BT_TEST(drp->dr_spilled, reg) == 0) {
+ if (BT_TEST(drp->dr_spilled, reg) == 0 &&
+ BT_TEST(drp->dr_nonspillable, reg) == 0) {
drp->dr_spill_store(reg);
BT_SET(drp->dr_spilled, reg);
return reg;
@@ -89,10 +95,11 @@ dt_regset_xalloc(dt_regset_t *drp, int reg)
assert(reg >= 0 && reg < drp->dr_size);
if (BT_TEST(drp->dr_active, reg) != 0) {
if (BT_TEST(drp->dr_spilled, reg) != 0)
- return -1; /* register in use (and spilled)*/
+ return -1; /* register in use (and spilled) */
drp->dr_spill_store(reg);
BT_SET(drp->dr_spilled, reg);
+ BT_CLEAR(drp->dr_nonspillable, reg);
}
BT_SET(drp->dr_active, reg);
@@ -109,12 +116,28 @@ dt_regset_free(dt_regset_t *drp, int reg)
if (BT_TEST(drp->dr_spilled, reg) != 0) {
drp->dr_spill_load(reg);
BT_CLEAR(drp->dr_spilled, reg);
+ BT_CLEAR(drp->dr_nonspillable, reg);
return;
}
BT_CLEAR(drp->dr_active, reg);
}
+/*
+ * Prevent the spill machinery from spilling a given reg (perhaps because of
+ * a live reference to this reg by number)
+ */
+void
+dt_regset_no_spill(dt_regset_t *drp, int reg, int nonspillable)
+{
+ if (nonspillable) {
+ BT_SET(drp->dr_nonspillable, reg);
+ } else {
+ BT_CLEAR(drp->dr_nonspillable, reg);
+ }
+}
+
+
/*
* Allocate %r1 through %r5 for use as function call arguments in BPF.
*/
diff --git a/libdtrace/dt_regset.h b/libdtrace/dt_regset.h
index 7ccb66d7d568..7e2756a11c45 100644
--- a/libdtrace/dt_regset.h
+++ b/libdtrace/dt_regset.h
@@ -25,6 +25,7 @@ typedef struct dt_regset {
dt_cg_spill_f dr_spill_load; /* register spill load function */
ulong_t *dr_active; /* bitmap of active registers */
ulong_t *dr_spilled; /* bitmap of spilled registers */
+ ulong_t *dr_nonspillable; /* bitmap of nonspillable registers */
} dt_regset_t;
extern dt_regset_t *dt_regset_create(ulong_t, dt_cg_spill_f, dt_cg_spill_f);
@@ -33,6 +34,7 @@ extern void dt_regset_reset(dt_regset_t *);
extern int dt_regset_alloc(dt_regset_t *);
extern int dt_regset_xalloc(dt_regset_t *, int);
extern void dt_regset_free(dt_regset_t *, int);
+extern void dt_regset_no_spill(dt_regset_t *, int reg, int nonspillable);
extern int dt_regset_xalloc_args(dt_regset_t *);
extern void dt_regset_free_args(dt_regset_t *);
extern void dt_regset_dump(dt_regset_t *, const char *);
--
2.36.1.263.g194b774378.dirty
More information about the DTrace-devel
mailing list