[DTrace-devel] [PATCH v4 19/20] Implement a framework for D subroutines incl. strlen() and speculation() implementation

Kris Van Hees kris.van.hees at oracle.com
Thu Jun 3 08:20:37 PDT 2021


This patch provides the skeleton for the implementation of subroutines
in D.  It is equivalent to the implementation of D actions in the code
generator.

The strlen() subroutine is provided as a first example of how to
imeplement subroutines.  The speculation() subroutine is provided as
an example of a dummy implementation.  It always simply returns 0, but
this allows various tests for the compiler to be exercised.

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 libdtrace/dt_cg.c                  | 130 ++++++++++++++++++++++++-----
 test/unittest/strlen/tst.strlen1.d |   3 +-
 2 files changed, 112 insertions(+), 21 deletions(-)

diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index e7cc00bc..8bb01852 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -661,16 +661,15 @@ dt_cg_fill_gap(dt_pcb_t *pcb, int gap)
 static void
 dt_cg_memcpy(dt_irlist_t *dlp, dt_regset_t *drp, int dst, int src, size_t size)
 {
-	dt_ident_t *idp;
+	dt_ident_t	*idp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_memcpy");
 
+	assert(idp != NULL);
 	if (dt_regset_xalloc_args(drp) == -1)
 		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
 
 	emit(dlp,  BPF_MOV_REG(BPF_REG_1, dst));
 	emit(dlp,  BPF_MOV_REG(BPF_REG_2, src));
 	emit(dlp,  BPF_MOV_IMM(BPF_REG_3, size));
-	idp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_memcpy");
-	assert(idp != NULL);
 	dt_regset_xalloc(drp, BPF_REG_0);
 	emite(dlp, BPF_CALL_FUNC(idp->di_id), idp);
 	dt_regset_free_args(drp);
@@ -678,6 +677,23 @@ dt_cg_memcpy(dt_irlist_t *dlp, dt_regset_t *drp, int dst, int src, size_t size)
 	dt_regset_free(drp, BPF_REG_0);
 }
 
+static void
+dt_cg_strlen(dt_irlist_t *dlp, dt_regset_t *drp, int dst, int src)
+{
+	dt_ident_t	*idp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_vint2int");
+
+	assert(idp != NULL);
+	if (dt_regset_xalloc_args(drp) == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+
+	emit(dlp, BPF_MOV_REG(BPF_REG_1, src));
+	dt_regset_xalloc(drp, BPF_REG_0);
+	emite(dlp,  BPF_CALL_FUNC(idp->di_id), idp);
+	emit(dlp, BPF_MOV_REG(dst, BPF_REG_0));
+	dt_regset_free_args(drp);
+	dt_regset_free(drp, BPF_REG_0);
+}
+
 static void
 dt_cg_spill_store(int reg)
 {
@@ -2786,6 +2802,97 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 	emit(dlp, BPF_ALU64_REG((dnp->dn_flags & DT_NF_SIGNED) ? BPF_ARSH : BPF_RSH, dnp->dn_reg, n));
 }
 
+static void
+dt_cg_subr_speculation(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+	TRACE_REGSET("    subr-speculation:Begin");
+	dnp->dn_reg = dt_regset_alloc(drp);
+	emit(dlp, BPF_MOV_IMM(dnp->dn_reg, 0));
+	TRACE_REGSET("    subr-speculation:End  ");
+}
+
+static void
+dt_cg_subr_strlen(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+	TRACE_REGSET("    subr-strlen:Begin");
+	dt_cg_node(dnp->dn_args, dlp, drp);
+	dnp->dn_reg = dnp->dn_args->dn_reg;
+	dt_cg_strlen(dlp, drp, dnp->dn_reg, dnp->dn_args->dn_reg);
+	TRACE_REGSET("    subr-strlen:End  ");
+}
+
+typedef void dt_cg_subr_f(dt_node_t *, dt_irlist_t *, dt_regset_t *);
+
+static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
+	[DIF_SUBR_RAND]			= NULL,
+	[DIF_SUBR_MUTEX_OWNED]		= NULL,
+	[DIF_SUBR_MUTEX_OWNER]		= NULL,
+	[DIF_SUBR_MUTEX_TYPE_ADAPTIVE]	= NULL,
+	[DIF_SUBR_MUTEX_TYPE_SPIN]	= NULL,
+	[DIF_SUBR_RW_READ_HELD]		= NULL,
+	[DIF_SUBR_RW_WRITE_HELD]	= NULL,
+	[DIF_SUBR_RW_ISWRITER]		= NULL,
+	[DIF_SUBR_COPYIN]		= NULL,
+	[DIF_SUBR_COPYINSTR]		= NULL,
+	[DIF_SUBR_SPECULATION]		= &dt_cg_subr_speculation,
+	[DIF_SUBR_PROGENYOF]		= NULL,
+	[DIF_SUBR_STRLEN]		= &dt_cg_subr_strlen,
+	[DIF_SUBR_COPYOUT]		= NULL,
+	[DIF_SUBR_COPYOUTSTR]		= NULL,
+	[DIF_SUBR_ALLOCA]		= NULL,
+	[DIF_SUBR_BCOPY]		= NULL,
+	[DIF_SUBR_COPYINTO]		= NULL,
+	[DIF_SUBR_MSGDSIZE]		= NULL,
+	[DIF_SUBR_MSGSIZE]		= NULL,
+	[DIF_SUBR_GETMAJOR]		= NULL,
+	[DIF_SUBR_GETMINOR]		= NULL,
+	[DIF_SUBR_DDI_PATHNAME]		= NULL,
+	[DIF_SUBR_STRJOIN]		= NULL,
+	[DIF_SUBR_LLTOSTR]		= NULL,
+	[DIF_SUBR_BASENAME]		= NULL,
+	[DIF_SUBR_DIRNAME]		= NULL,
+	[DIF_SUBR_CLEANPATH]		= NULL,
+	[DIF_SUBR_STRCHR]		= NULL,
+	[DIF_SUBR_STRRCHR]		= NULL,
+	[DIF_SUBR_STRSTR]		= NULL,
+	[DIF_SUBR_STRTOK]		= NULL,
+	[DIF_SUBR_SUBSTR]		= NULL,
+	[DIF_SUBR_INDEX]		= NULL,
+	[DIF_SUBR_RINDEX]		= NULL,
+	[DIF_SUBR_HTONS]		= NULL,
+	[DIF_SUBR_HTONL]		= NULL,
+	[DIF_SUBR_HTONLL]		= NULL,
+	[DIF_SUBR_NTOHS]		= NULL,
+	[DIF_SUBR_NTOHL]		= NULL,
+	[DIF_SUBR_NTOHLL]		= NULL,
+	[DIF_SUBR_INET_NTOP]		= NULL,
+	[DIF_SUBR_INET_NTOA]		= NULL,
+	[DIF_SUBR_INET_NTOA6]		= NULL,
+	[DIF_SUBR_D_PATH]		= NULL,
+	[DIF_SUBR_LINK_NTOP]		= NULL,
+};
+
+static void
+dt_cg_call_subr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+	dt_ident_t	*idp = dnp->dn_ident;
+	dt_cg_subr_f	*fun;
+
+	if (idp->di_kind != DT_IDENT_FUNC)
+		dnerror(dnp, D_CG_EXPR, "%s %s( ) may not be called from a D "
+					"expression (D program context "
+					"required)\n",
+			dt_idkind_name(idp->di_kind), idp->di_name);
+
+	assert(idp->di_id > 0 && idp->di_id <= DIF_SUBR_MAX);
+
+	fun = _dt_cg_subr[idp->di_id];
+	if (fun == NULL)
+		dnerror(dnp, D_FUNC_UNDEF, "unimplemented subroutine: %s\n",
+			idp->di_name);
+	fun(dnp, dlp, drp);
+}
+
 /*
  * Generate code for an inlined variable reference.  Inlines can be used to
  * define either scalar or associative array substitutions.  For scalars, we
@@ -3291,22 +3398,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 
 		switch (dnp->dn_kind) {
 		case DT_NODE_FUNC:
-			if ((idp = dnp->dn_ident)->di_kind != DT_IDENT_FUNC) {
-				dnerror(dnp, D_CG_EXPR, "%s %s( ) may not be "
-				    "called from a D expression (D program "
-				    "context required)\n",
-				    dt_idkind_name(idp->di_kind), idp->di_name);
-			}
-
-			dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);
-
-			if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
-				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
-
-/* FIXME */
-			emit(dlp, BPF_CALL_HELPER(-dnp->dn_ident->di_id));
-			emit(dlp, BPF_MOV_REG(dnp->dn_reg, BPF_REG_0));
-
+			dt_cg_call_subr(dnp, dlp, drp);
 			break;
 
 		case DT_NODE_VAR: {
diff --git a/test/unittest/strlen/tst.strlen1.d b/test/unittest/strlen/tst.strlen1.d
index 1fed2fb2..aed5623c 100644
--- a/test/unittest/strlen/tst.strlen1.d
+++ b/test/unittest/strlen/tst.strlen1.d
@@ -1,10 +1,9 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION:
-- 
2.31.1




More information about the DTrace-devel mailing list