[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