aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dstyle.pl9
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.else.d33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if.d33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if2.d33
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_before_after.d46
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_nested.d38
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon.d30
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon2.d31
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c27
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y34
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h3
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c8
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c282
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h16
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c516
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h9
-rw-r--r--cddl/lib/libdtrace/Makefile1
17 files changed, 1095 insertions, 54 deletions
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dstyle.pl b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dstyle.pl
index 3c3e180a0e75..30b54d850733 100755
--- a/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dstyle.pl
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dstyle.pl
@@ -25,6 +25,10 @@
# Use is subject to license terms.
#
+#
+# Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+#
+
require 5.8.4;
$PNAME = $0;
@@ -131,7 +135,8 @@ sub dstyle
}
if (!/^enum/ && !/^\t*struct/ && !/^\t*union/ && !/^typedef/ &&
- !/^translator/ && !/^provider/) {
+ !/^translator/ && !/^provider/ && !/\tif / &&
+ !/ else /) {
if (/[\w\s]+{/) {
err "left brace not on its own line";
}
@@ -141,7 +146,7 @@ sub dstyle
}
}
- if (!/;$/) {
+ if (!/;$/ && !/\t*}$/ && !/ else /) {
if (/[\w\s]+}/) {
err "right brace not on its own line";
}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.else.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.else.d
new file mode 100644
index 000000000000..88da007436fb
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.else.d
@@ -0,0 +1,33 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * "else" statement is executed
+ */
+
+BEGIN
+{
+ if (0) {
+ n = 1;
+ } else {
+ n = 0;
+ }
+ exit(n)
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if.d
new file mode 100644
index 000000000000..3da5d2daf695
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if.d
@@ -0,0 +1,33 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * "if" statement executes the correct body.
+ */
+
+BEGIN
+{
+ if (1) {
+ n = 0;
+ } else {
+ n = 1;
+ }
+ exit(n)
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if2.d
new file mode 100644
index 000000000000..b56e39929d67
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if2.d
@@ -0,0 +1,33 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * "if" statement executes the correct body.
+ * parses single-statement, braceless bodies correctly.
+ */
+
+BEGIN
+{
+ if (1)
+ n = 0;
+ else
+ n = 1;
+ exit(n)
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_before_after.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_before_after.d
new file mode 100644
index 000000000000..00837eb65c2c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_before_after.d
@@ -0,0 +1,46 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * statements before and after an if statement are executed.
+ */
+
+BEGIN
+{
+ i = 1;
+ if (1) {
+ i++;
+ } else {
+ i++;
+ }
+ i++;
+}
+
+BEGIN
+/i == 3/
+{
+ exit(0);
+}
+
+BEGIN
+/i != 3/
+{
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_nested.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_nested.d
new file mode 100644
index 000000000000..e8ad443a04bd
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_nested.d
@@ -0,0 +1,38 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * nested "if" statement executes the correct body.
+ */
+
+BEGIN
+{
+ if (0) {
+ exit(1);
+ } else {
+ if (0) {
+ exit(1);
+ } else {
+ exit(0);
+ }
+ exit(1);
+ }
+ exit(1);
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon.d
new file mode 100644
index 000000000000..81196c0ca47c
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon.d
@@ -0,0 +1,30 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * "if" body without trailing semicolon parses correctly
+ */
+
+BEGIN
+{
+ if (1) {
+ exit(0)
+ }
+}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon2.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon2.d
new file mode 100644
index 000000000000..e1bd3895f9f0
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon2.d
@@ -0,0 +1,31 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * ASSERTION:
+ * "if" body without trailing semicolon parses correctly
+ */
+
+BEGIN
+{
+ if (1) {
+ i = 1;
+ exit(0)
+ }
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c
index cf69befa6b99..ef10e0bc7e94 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c
@@ -21,8 +21,8 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent Inc. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright 2015 Gary Mills
*/
@@ -120,7 +120,6 @@ static const dtrace_diftype_t dt_int_rtype = {
static void *dt_compile(dtrace_hdl_t *, int, dtrace_probespec_t, void *,
uint_t, int, char *const[], FILE *, const char *);
-
/*ARGSUSED*/
static int
dt_idreset(dt_idhash_t *dhp, dt_ident_t *idp, void *ignored)
@@ -2519,6 +2518,28 @@ dt_compile(dtrace_hdl_t *dtp, int context, dtrace_probespec_t pspec, void *arg,
}
/*
+ * Perform sugar transformations (for "if" / "else") and replace the
+ * existing clause chain with the new one.
+ */
+ if (context == DT_CTX_DPROG) {
+ dt_node_t *dnp, *next_dnp;
+ dt_node_t *new_list = NULL;
+
+ for (dnp = yypcb->pcb_root->dn_list;
+ dnp != NULL; dnp = next_dnp) {
+ /* remove this node from the list */
+ next_dnp = dnp->dn_list;
+ dnp->dn_list = NULL;
+
+ if (dnp->dn_kind == DT_NODE_CLAUSE)
+ dnp = dt_compile_sugar(dtp, dnp);
+ /* append node to the new list */
+ new_list = dt_node_link(new_list, dnp);
+ }
+ yypcb->pcb_root->dn_list = new_list;
+ }
+
+ /*
* If we have successfully created a parse tree for a D program, loop
* over the clauses and actions and instantiate the corresponding
* libdtrace program. If we are parsing a D expression, then we
@@ -2538,6 +2559,8 @@ dt_compile(dtrace_hdl_t *dtp, int context, dtrace_probespec_t pspec, void *arg,
for (; dnp != NULL; dnp = dnp->dn_list) {
switch (dnp->dn_kind) {
case DT_NODE_CLAUSE:
+ if (DT_TREEDUMP_PASS(dtp, 4))
+ dt_printd(dnp, stderr, 0);
dt_compile_clause(dtp, dnp);
break;
case DT_NODE_XLATOR:
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y
index 6321b65808d3..0cb6fa6b5253 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y
@@ -23,8 +23,9 @@
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+
/*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
@@ -155,6 +156,8 @@
%type <l_node> probe_specifier_list
%type <l_node> probe_specifier
%type <l_node> statement_list
+%type <l_node> statement_list_impl
+%type <l_node> statement_or_block
%type <l_node> statement
%type <l_node> declaration
%type <l_node> init_declarator_list
@@ -319,9 +322,11 @@ probe_definition:
"or actions following probe description\n");
}
$$ = dt_node_clause($1, NULL, NULL);
+ yybegin(YYS_CLAUSE);
}
| probe_specifiers '{' statement_list '}' {
$$ = dt_node_clause($1, NULL, $3);
+ yybegin(YYS_CLAUSE);
}
| probe_specifiers DT_TOK_DIV expression DT_TOK_EPRED {
dnerror($3, D_SYNTAX, "expected actions { } following "
@@ -330,6 +335,7 @@ probe_definition:
| probe_specifiers DT_TOK_DIV expression DT_TOK_EPRED
'{' statement_list '}' {
$$ = dt_node_clause($1, $3, $6);
+ yybegin(YYS_CLAUSE);
}
;
@@ -349,12 +355,30 @@ probe_specifier:
| DT_TOK_INT { $$ = dt_node_pdesc_by_id($1); }
;
-statement_list: statement { $$ = $1; }
- | statement_list ';' statement { $$ = LINK($1, $3); }
+statement_list_impl: /* empty */ { $$ = NULL; }
+ | statement_list_impl statement { $$ = LINK($1, $2); }
+ ;
+
+statement_list:
+ statement_list_impl { $$ = $1; }
+ | statement_list_impl expression {
+ $$ = LINK($1, dt_node_statement($2));
+ }
;
-statement: /* empty */ { $$ = NULL; }
- | expression { $$ = dt_node_statement($1); }
+statement_or_block:
+ statement
+ | '{' statement_list '}' { $$ = $2; }
+
+statement: ';' { $$ = NULL; }
+ | expression ';' { $$ = dt_node_statement($1); }
+ | DT_KEY_IF DT_TOK_LPAR expression DT_TOK_RPAR statement_or_block {
+ $$ = dt_node_if($3, $5, NULL);
+ }
+ | DT_KEY_IF DT_TOK_LPAR expression DT_TOK_RPAR
+ statement_or_block DT_KEY_ELSE statement_or_block {
+ $$ = dt_node_if($3, $5, $7);
+ }
;
argument_expression_list:
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
index 36cc5396e214..e71e9d71aeff 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
@@ -26,7 +26,7 @@
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
*/
#ifndef _DT_IMPL_H
@@ -362,6 +362,7 @@ struct dtrace_hdl {
int dt_indent; /* recommended flow indent */
dtrace_epid_t dt_last_epid; /* most recently consumed EPID */
uint64_t dt_last_timestamp; /* most recently consumed timestamp */
+ boolean_t dt_has_sugar; /* syntactic sugar used? */
};
/*
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
index ac0524b07050..a56b98681d3b 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
*/
#include <sys/types.h>
@@ -130,8 +130,9 @@
#define DT_VERS_1_11 DT_VERSION_NUMBER(1, 11, 0)
#define DT_VERS_1_12 DT_VERSION_NUMBER(1, 12, 0)
#define DT_VERS_1_12_1 DT_VERSION_NUMBER(1, 12, 1)
-#define DT_VERS_LATEST DT_VERS_1_12_1
-#define DT_VERS_STRING "Sun D 1.12.1"
+#define DT_VERS_1_13 DT_VERSION_NUMBER(1, 13, 0)
+#define DT_VERS_LATEST DT_VERS_1_13
+#define DT_VERS_STRING "Sun D 1.13"
const dt_version_t _dtrace_versions[] = {
DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */
@@ -157,6 +158,7 @@ const dt_version_t _dtrace_versions[] = {
DT_VERS_1_11, /* D API 1.11 */
DT_VERS_1_12, /* D API 1.12 */
DT_VERS_1_12_1, /* D API 1.12.1 */
+ DT_VERS_1_13, /* D API 1.13 */
0
};
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c
index ee31cef5f28c..5af7a00a80fe 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c
@@ -23,7 +23,7 @@
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) 2013, Joyent Inc. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -2143,6 +2143,17 @@ dt_node_statement(dt_node_t *expr)
}
dt_node_t *
+dt_node_if(dt_node_t *pred, dt_node_t *acts, dt_node_t *else_acts)
+{
+ dt_node_t *dnp = dt_node_alloc(DT_NODE_IF);
+ dnp->dn_conditional = pred;
+ dnp->dn_body = acts;
+ dnp->dn_alternate_body = else_acts;
+
+ return (dnp);
+}
+
+dt_node_t *
dt_node_pdesc_by_name(char *spec)
{
dtrace_hdl_t *dtp = yypcb->pcb_hdl;
@@ -2211,7 +2222,6 @@ dt_node_clause(dt_node_t *pdescs, dt_node_t *pred, dt_node_t *acts)
dnp->dn_pred = pred;
dnp->dn_acts = acts;
- yybegin(YYS_CLAUSE);
return (dnp);
}
@@ -3203,8 +3213,9 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags)
dt_xcook_ident(lp, dhp, idkind, B_TRUE);
else
dt_xcook_ident(lp, dhp, idp->di_kind, B_FALSE);
- } else
+ } else {
lp = dnp->dn_left = dt_node_cook(lp, 0);
+ }
/*
* Switch op to '+' for *(E1 + E2) array mode in these cases:
@@ -3218,10 +3229,12 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags)
if (lp->dn_ident->di_kind == DT_IDENT_ARRAY) {
if (lp->dn_args != NULL)
op = DT_TOK_ADD;
- } else if (!dt_ident_unref(lp->dn_ident))
+ } else if (!dt_ident_unref(lp->dn_ident)) {
op = DT_TOK_ADD;
- } else if (lp->dn_kind != DT_NODE_AGG)
+ }
+ } else if (lp->dn_kind != DT_NODE_AGG) {
op = DT_TOK_ADD;
+ }
}
switch (op) {
@@ -3645,45 +3658,34 @@ asgn_common:
case DT_TOK_PTR:
/*
- * If the left-hand side of operator -> is the name "self",
- * then we permit a TLS variable to be created or referenced.
+ * If the left-hand side of operator -> is one of the scoping
+ * keywords, permit a local or thread variable to be created or
+ * referenced.
*/
- if (lp->dn_kind == DT_NODE_IDENT &&
- strcmp(lp->dn_string, "self") == 0) {
- if (rp->dn_kind != DT_NODE_VAR) {
- dt_xcook_ident(rp, dtp->dt_tls,
- DT_IDENT_SCALAR, B_TRUE);
- }
-
- if (idflags != 0)
- rp = dt_node_cook(rp, idflags);
-
- dnp->dn_right = dnp->dn_left; /* avoid freeing rp */
- dt_node_free(dnp);
- return (rp);
- }
+ if (lp->dn_kind == DT_NODE_IDENT) {
+ dt_idhash_t *dhp = NULL;
- /*
- * If the left-hand side of operator -> is the name "this",
- * then we permit a local variable to be created or referenced.
- */
- if (lp->dn_kind == DT_NODE_IDENT &&
- strcmp(lp->dn_string, "this") == 0) {
- if (rp->dn_kind != DT_NODE_VAR) {
- dt_xcook_ident(rp, yypcb->pcb_locals,
- DT_IDENT_SCALAR, B_TRUE);
+ if (strcmp(lp->dn_string, "self") == 0) {
+ dhp = dtp->dt_tls;
+ } else if (strcmp(lp->dn_string, "this") == 0) {
+ dhp = yypcb->pcb_locals;
}
+ if (dhp != NULL) {
+ if (rp->dn_kind != DT_NODE_VAR) {
+ dt_xcook_ident(rp, dhp,
+ DT_IDENT_SCALAR, B_TRUE);
+ }
- if (idflags != 0)
- rp = dt_node_cook(rp, idflags);
+ if (idflags != 0)
+ rp = dt_node_cook(rp, idflags);
- dnp->dn_right = dnp->dn_left; /* avoid freeing rp */
- dt_node_free(dnp);
- return (rp);
+ /* avoid freeing rp */
+ dnp->dn_right = dnp->dn_left;
+ dt_node_free(dnp);
+ return (rp);
+ }
}
-
/*FALLTHRU*/
-
case DT_TOK_DOT:
lp = dnp->dn_left = dt_node_cook(lp, DT_IDFLG_REF);
@@ -4502,7 +4504,8 @@ static dt_node_t *(*dt_cook_funcs[])(dt_node_t *, uint_t) = {
dt_cook_xlator, /* DT_NODE_XLATOR */
dt_cook_none, /* DT_NODE_PROBE */
dt_cook_provider, /* DT_NODE_PROVIDER */
- dt_cook_none /* DT_NODE_PROG */
+ dt_cook_none, /* DT_NODE_PROG */
+ dt_cook_none, /* DT_NODE_IF */
};
/*
@@ -4517,6 +4520,8 @@ dt_node_cook(dt_node_t *dnp, uint_t idflags)
yylineno = dnp->dn_line;
+ assert(dnp->dn_kind <
+ sizeof (dt_cook_funcs) / sizeof (dt_cook_funcs[0]));
dnp = dt_cook_funcs[dnp->dn_kind](dnp, idflags);
dnp->dn_flags |= DT_NF_COOKED;
@@ -4619,6 +4624,181 @@ dt_node_diftype(dtrace_hdl_t *dtp, const dt_node_t *dnp, dtrace_diftype_t *tp)
tp->dtdt_size = ctf_type_size(dnp->dn_ctfp, dnp->dn_type);
}
+/*
+ * Output the parse tree as D. The "-xtree=8" argument will call this
+ * function to print out the program after any syntactic sugar
+ * transformations have been applied (e.g. to implement "if"). The
+ * resulting output can be used to understand the transformations
+ * applied by these features, or to run such a script on a system that
+ * does not support these features
+ *
+ * Note that the output does not express precisely the same program as
+ * the input. In particular:
+ * - Only the clauses are output. #pragma options, variable
+ * declarations, etc. are excluded.
+ * - Command argument substitution has already been done, so the output
+ * will not contain e.g. $$1, but rather the substituted string.
+ */
+void
+dt_printd(dt_node_t *dnp, FILE *fp, int depth)
+{
+ dt_node_t *arg;
+
+ switch (dnp->dn_kind) {
+ case DT_NODE_INT:
+ (void) fprintf(fp, "0x%llx", (u_longlong_t)dnp->dn_value);
+ if (!(dnp->dn_flags & DT_NF_SIGNED))
+ (void) fprintf(fp, "u");
+ break;
+
+ case DT_NODE_STRING: {
+ char *escd = strchr2esc(dnp->dn_string, strlen(dnp->dn_string));
+ (void) fprintf(fp, "\"%s\"", escd);
+ free(escd);
+ break;
+ }
+
+ case DT_NODE_IDENT:
+ (void) fprintf(fp, "%s", dnp->dn_string);
+ break;
+
+ case DT_NODE_VAR:
+ (void) fprintf(fp, "%s%s",
+ (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL) ? "this->" :
+ (dnp->dn_ident->di_flags & DT_IDFLG_TLS) ? "self->" : "",
+ dnp->dn_ident->di_name);
+
+ if (dnp->dn_args != NULL) {
+ (void) fprintf(fp, "[");
+
+ for (arg = dnp->dn_args; arg != NULL;
+ arg = arg->dn_list) {
+ dt_printd(arg, fp, 0);
+ if (arg->dn_list != NULL)
+ (void) fprintf(fp, ", ");
+ }
+
+ (void) fprintf(fp, "]");
+ }
+ break;
+
+ case DT_NODE_SYM: {
+ const dtrace_syminfo_t *dts = dnp->dn_ident->di_data;
+ (void) fprintf(fp, "%s`%s", dts->dts_object, dts->dts_name);
+ break;
+ }
+ case DT_NODE_FUNC:
+ (void) fprintf(fp, "%s(", dnp->dn_ident->di_name);
+
+ for (arg = dnp->dn_args; arg != NULL; arg = arg->dn_list) {
+ dt_printd(arg, fp, 0);
+ if (arg->dn_list != NULL)
+ (void) fprintf(fp, ", ");
+ }
+ (void) fprintf(fp, ")");
+ break;
+
+ case DT_NODE_OP1:
+ (void) fprintf(fp, "%s(", opstr(dnp->dn_op));
+ dt_printd(dnp->dn_child, fp, 0);
+ (void) fprintf(fp, ")");
+ break;
+
+ case DT_NODE_OP2:
+ (void) fprintf(fp, "(");
+ dt_printd(dnp->dn_left, fp, 0);
+ if (dnp->dn_op == DT_TOK_LPAR) {
+ (void) fprintf(fp, ")");
+ dt_printd(dnp->dn_right, fp, 0);
+ break;
+ }
+ if (dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT ||
+ dnp->dn_op == DT_TOK_LBRAC)
+ (void) fprintf(fp, "%s", opstr(dnp->dn_op));
+ else
+ (void) fprintf(fp, " %s ", opstr(dnp->dn_op));
+ dt_printd(dnp->dn_right, fp, 0);
+ if (dnp->dn_op == DT_TOK_LBRAC) {
+ dt_node_t *ln = dnp->dn_right;
+ while (ln->dn_list != NULL) {
+ (void) fprintf(fp, ", ");
+ dt_printd(ln->dn_list, fp, depth);
+ ln = ln->dn_list;
+ }
+ (void) fprintf(fp, "]");
+ }
+ (void) fprintf(fp, ")");
+ break;
+
+ case DT_NODE_OP3:
+ (void) fprintf(fp, "(");
+ dt_printd(dnp->dn_expr, fp, 0);
+ (void) fprintf(fp, " ? ");
+ dt_printd(dnp->dn_left, fp, 0);
+ (void) fprintf(fp, " : ");
+ dt_printd(dnp->dn_right, fp, 0);
+ (void) fprintf(fp, ")");
+ break;
+
+ case DT_NODE_DEXPR:
+ case DT_NODE_DFUNC:
+ (void) fprintf(fp, "%*s", depth * 8, "");
+ dt_printd(dnp->dn_expr, fp, depth + 1);
+ (void) fprintf(fp, ";\n");
+ break;
+
+ case DT_NODE_PDESC:
+ (void) fprintf(fp, "%s:%s:%s:%s",
+ dnp->dn_desc->dtpd_provider, dnp->dn_desc->dtpd_mod,
+ dnp->dn_desc->dtpd_func, dnp->dn_desc->dtpd_name);
+ break;
+
+ case DT_NODE_CLAUSE:
+ for (arg = dnp->dn_pdescs; arg != NULL; arg = arg->dn_list) {
+ dt_printd(arg, fp, 0);
+ if (arg->dn_list != NULL)
+ (void) fprintf(fp, ",");
+ (void) fprintf(fp, "\n");
+ }
+
+ if (dnp->dn_pred != NULL) {
+ (void) fprintf(fp, "/");
+ dt_printd(dnp->dn_pred, fp, 0);
+ (void) fprintf(fp, "/\n");
+ }
+ (void) fprintf(fp, "{\n");
+
+ for (arg = dnp->dn_acts; arg != NULL; arg = arg->dn_list)
+ dt_printd(arg, fp, depth + 1);
+ (void) fprintf(fp, "}\n");
+ (void) fprintf(fp, "\n");
+ break;
+
+ case DT_NODE_IF:
+ (void) fprintf(fp, "%*sif (", depth * 8, "");
+ dt_printd(dnp->dn_conditional, fp, 0);
+ (void) fprintf(fp, ") {\n");
+
+ for (arg = dnp->dn_body; arg != NULL; arg = arg->dn_list)
+ dt_printd(arg, fp, depth + 1);
+ if (dnp->dn_alternate_body == NULL) {
+ (void) fprintf(fp, "%*s}\n", depth * 8, "");
+ } else {
+ (void) fprintf(fp, "%*s} else {\n", depth * 8, "");
+ for (arg = dnp->dn_alternate_body; arg != NULL;
+ arg = arg->dn_list)
+ dt_printd(arg, fp, depth + 1);
+ (void) fprintf(fp, "%*s}\n", depth * 8, "");
+ }
+
+ break;
+
+ default:
+ (void) fprintf(fp, "/* bad node %p, kind %d */\n",
+ (void *)dnp, dnp->dn_kind);
+ }
+}
+
void
dt_node_printr(dt_node_t *dnp, FILE *fp, int depth)
{
@@ -4729,6 +4909,13 @@ dt_node_printr(dt_node_t *dnp, FILE *fp, int depth)
(void) fprintf(fp, "OP2 %s (%s)\n", opstr(dnp->dn_op), buf);
dt_node_printr(dnp->dn_left, fp, depth + 1);
dt_node_printr(dnp->dn_right, fp, depth + 1);
+ if (dnp->dn_op == DT_TOK_LBRAC) {
+ dt_node_t *ln = dnp->dn_right;
+ while (ln->dn_list != NULL) {
+ dt_node_printr(ln->dn_list, fp, depth + 1);
+ ln = ln->dn_list;
+ }
+ }
break;
case DT_NODE_OP3:
@@ -4790,6 +4977,7 @@ dt_node_printr(dt_node_t *dnp, FILE *fp, int depth)
for (arg = dnp->dn_acts; arg != NULL; arg = arg->dn_list)
dt_node_printr(arg, fp, depth + 1);
+ (void) fprintf(fp, "\n");
break;
case DT_NODE_INLINE:
@@ -4840,6 +5028,24 @@ dt_node_printr(dt_node_t *dnp, FILE *fp, int depth)
dt_node_printr(arg, fp, depth + 1);
break;
+ case DT_NODE_IF:
+ (void) fprintf(fp, "IF attr=%s CONDITION:\n", a);
+
+ dt_node_printr(dnp->dn_conditional, fp, depth + 1);
+
+ (void) fprintf(fp, "%*sIF BODY: \n", depth * 2, "");
+ for (arg = dnp->dn_body; arg != NULL; arg = arg->dn_list)
+ dt_node_printr(arg, fp, depth + 1);
+
+ if (dnp->dn_alternate_body != NULL) {
+ (void) fprintf(fp, "%*sIF ELSE: \n", depth * 2, "");
+ for (arg = dnp->dn_alternate_body; arg != NULL;
+ arg = arg->dn_list)
+ dt_node_printr(arg, fp, depth + 1);
+ }
+
+ break;
+
default:
(void) fprintf(fp, "<bad node %p, kind %d>\n",
(void *)dnp, dnp->dn_kind);
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h
index 38f21c9f2e9e..3a146c5d2592 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h
@@ -23,7 +23,7 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, 2016 by Delphix. All rights reserved.
* Copyright (c) 2013 Joyent, Inc. All rights reserved.
*/
@@ -105,6 +105,12 @@ typedef struct dt_node {
struct dt_node *_probes; /* list of probe nodes */
int _redecl; /* provider redeclared */
} _provider;
+
+ struct {
+ struct dt_node *_conditional;
+ struct dt_node *_body;
+ struct dt_node *_alternate_body;
+ } _conditional;
} dn_u;
struct dt_node *dn_list; /* parse tree list link */
@@ -140,6 +146,11 @@ typedef struct dt_node {
#define dn_provred dn_u._provider._redecl /* DT_NODE_PROVIDER */
#define dn_probes dn_u._provider._probes /* DT_NODE_PROVIDER */
+/* DT_NODE_IF: */
+#define dn_conditional dn_u._conditional._conditional
+#define dn_body dn_u._conditional._body
+#define dn_alternate_body dn_u._conditional._alternate_body
+
#define DT_NODE_FREE 0 /* unused node (waiting to be freed) */
#define DT_NODE_INT 1 /* integer value */
#define DT_NODE_STRING 2 /* string value */
@@ -162,6 +173,7 @@ typedef struct dt_node {
#define DT_NODE_PROBE 19 /* probe definition */
#define DT_NODE_PROVIDER 20 /* provider definition */
#define DT_NODE_PROG 21 /* program translation unit */
+#define DT_NODE_IF 22 /* if statement */
#define DT_NF_SIGNED 0x01 /* data is a signed quantity (else unsigned) */
#define DT_NF_COOKED 0x02 /* data is a known type (else still cooking) */
@@ -213,6 +225,7 @@ extern dt_node_t *dt_node_xlator(dt_decl_t *, dt_decl_t *, char *, dt_node_t *);
extern dt_node_t *dt_node_probe(char *, int, dt_node_t *, dt_node_t *);
extern dt_node_t *dt_node_provider(char *, dt_node_t *);
extern dt_node_t *dt_node_program(dt_node_t *);
+extern dt_node_t *dt_node_if(dt_node_t *, dt_node_t *, dt_node_t *);
extern dt_node_t *dt_node_link(dt_node_t *, dt_node_t *);
extern dt_node_t *dt_node_cook(dt_node_t *, uint_t);
@@ -237,6 +250,7 @@ extern void dt_node_promote(dt_node_t *, dt_node_t *, dt_node_t *);
extern void dt_node_diftype(dtrace_hdl_t *,
const dt_node_t *, dtrace_diftype_t *);
extern void dt_node_printr(dt_node_t *, FILE *, int);
+extern void dt_printd(dt_node_t *, FILE *, int);
extern const char *dt_node_name(const dt_node_t *, char *, size_t);
extern int dt_node_root(dt_node_t *);
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c
new file mode 100644
index 000000000000..8bd052384d68
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c
@@ -0,0 +1,516 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ */
+
+/*
+ * Syntactic sugar features are implemented by transforming the D parse tree
+ * such that it only uses the subset of D that is supported by the rest of the
+ * compiler / the kernel. A clause containing these language features is
+ * referred to as a "super-clause", and its transformation typically entails
+ * creating several "sub-clauses" to implement it. For diagnosability, the
+ * sub-clauses will be printed if the "-xtree=8" flag is specified.
+ *
+ * Currently, the only syntactic sugar feature is "if/else" statements. Each
+ * basic block (e.g. the body of the "if" and "else" statements, and the
+ * statements before and after) is turned into its own sub-clause, with a
+ * predicate that causes it to be executed only if the code flows to this point.
+ * Nested if/else statements are supported.
+ *
+ * This infrastructure is designed to accommodate other syntactic sugar features
+ * in the future.
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/sysmacros.h>
+
+#include <assert.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <dt_module.h>
+#include <dt_program.h>
+#include <dt_provider.h>
+#include <dt_printf.h>
+#include <dt_pid.h>
+#include <dt_grammar.h>
+#include <dt_ident.h>
+#include <dt_string.h>
+#include <dt_impl.h>
+
+typedef struct dt_sugar_parse {
+ dtrace_hdl_t *dtsp_dtp; /* dtrace handle */
+ dt_node_t *dtsp_pdescs; /* probe descriptions */
+ int dtsp_num_conditions; /* number of condition variables */
+ int dtsp_num_ifs; /* number of "if" statements */
+ dt_node_t *dtsp_clause_list; /* list of clauses */
+} dt_sugar_parse_t;
+
+static void dt_sugar_visit_stmts(dt_sugar_parse_t *, dt_node_t *, int);
+
+/*
+ * Return a node for "self->%error".
+ *
+ * Note that the "%" is part of the variable name, and is included so that
+ * this variable name can not collide with any user-specified variable.
+ *
+ * This error variable is used to keep track of if there has been an error
+ * in any of the sub-clauses, and is used to prevent execution of subsequent
+ * sub-clauses following an error.
+ */
+static dt_node_t *
+dt_sugar_new_error_var(void)
+{
+ return (dt_node_op2(DT_TOK_PTR, dt_node_ident(strdup("self")),
+ dt_node_ident(strdup("%error"))));
+}
+
+/*
+ * Append this clause to the clause list.
+ */
+static void
+dt_sugar_append_clause(dt_sugar_parse_t *dp, dt_node_t *clause)
+{
+ dp->dtsp_clause_list = dt_node_link(dp->dtsp_clause_list, clause);
+}
+
+/*
+ * Prepend this clause to the clause list.
+ */
+static void
+dt_sugar_prepend_clause(dt_sugar_parse_t *dp, dt_node_t *clause)
+{
+ dp->dtsp_clause_list = dt_node_link(clause, dp->dtsp_clause_list);
+}
+
+/*
+ * Return a node for "this->%condition_<condid>", or NULL if condid==0.
+ *
+ * Note that the "%" is part of the variable name, and is included so that
+ * this variable name can not collide with any user-specified variable.
+ */
+static dt_node_t *
+dt_sugar_new_condition_var(int condid)
+{
+ char *str;
+
+ if (condid == 0)
+ return (NULL);
+ assert(condid > 0);
+
+ (void) asprintf(&str, "%%condition_%d", ABS(condid));
+ return (dt_node_op2(DT_TOK_PTR, dt_node_ident(strdup("this")),
+ dt_node_ident(str)));
+}
+
+/*
+ * Return new clause to evaluate predicate and set newcond. condid is
+ * the condition that we are already under, or 0 if none.
+ * The new clause will be of the form:
+ *
+ * dp_pdescs
+ * /!self->%error/
+ * {
+ * this->%condition_<newcond> =
+ * (this->%condition_<condid> && pred);
+ * }
+ *
+ * Note: if condid==0, we will instead do "... = (1 && pred)", to effectively
+ * convert the pred to a boolean.
+ *
+ * Note: Unless an error has been encountered, we always set the condition
+ * variable (either to 0 or 1). This lets us avoid resetting the condition
+ * variables back to 0 when the super-clause completes.
+ */
+static dt_node_t *
+dt_sugar_new_condition_impl(dt_sugar_parse_t *dp,
+ dt_node_t *pred, int condid, int newcond)
+{
+ dt_node_t *value, *body, *newpred;
+
+ /* predicate is !self->%error */
+ newpred = dt_node_op1(DT_TOK_LNEG, dt_sugar_new_error_var());
+
+ if (condid == 0) {
+ /*
+ * value is (1 && pred)
+ *
+ * Note, D doesn't allow a probe-local "this" variable to
+ * be reused as a different type, even from a different probe.
+ * Therefore, value can't simply be <pred>, because then
+ * its type could be different when we reuse this condid
+ * in a different meta-clause.
+ */
+ value = dt_node_op2(DT_TOK_LAND, dt_node_int(1), pred);
+ } else {
+ /* value is (this->%condition_<condid> && pred) */
+ value = dt_node_op2(DT_TOK_LAND,
+ dt_sugar_new_condition_var(condid), pred);
+ }
+
+ /* body is "this->%condition_<retval> = <value>;" */
+ body = dt_node_statement(dt_node_op2(DT_TOK_ASGN,
+ dt_sugar_new_condition_var(newcond), value));
+
+ return (dt_node_clause(dp->dtsp_pdescs, newpred, body));
+}
+
+/*
+ * Generate a new clause to evaluate predicate and set a new condition variable,
+ * whose ID will be returned. The new clause will be appended to
+ * dp_first_new_clause.
+ */
+static int
+dt_sugar_new_condition(dt_sugar_parse_t *dp, dt_node_t *pred, int condid)
+{
+ dp->dtsp_num_conditions++;
+ dt_sugar_append_clause(dp, dt_sugar_new_condition_impl(dp,
+ pred, condid, dp->dtsp_num_conditions));
+ return (dp->dtsp_num_conditions);
+}
+
+/*
+ * Visit the specified node and all of its descendants. Currently this is only
+ * used to count the number of "if" statements (dtsp_num_ifs).
+ */
+static void
+dt_sugar_visit_all(dt_sugar_parse_t *dp, dt_node_t *dnp)
+{
+ dt_node_t *arg;
+
+ switch (dnp->dn_kind) {
+ case DT_NODE_FREE:
+ case DT_NODE_INT:
+ case DT_NODE_STRING:
+ case DT_NODE_SYM:
+ case DT_NODE_TYPE:
+ case DT_NODE_PROBE:
+ case DT_NODE_PDESC:
+ case DT_NODE_IDENT:
+ break;
+
+ case DT_NODE_FUNC:
+ for (arg = dnp->dn_args; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+ break;
+
+ case DT_NODE_OP1:
+ dt_sugar_visit_all(dp, dnp->dn_child);
+ break;
+
+ case DT_NODE_OP2:
+ dt_sugar_visit_all(dp, dnp->dn_left);
+ dt_sugar_visit_all(dp, dnp->dn_right);
+ if (dnp->dn_op == DT_TOK_LBRAC) {
+ dt_node_t *ln = dnp->dn_right;
+ while (ln->dn_list != NULL) {
+ dt_sugar_visit_all(dp, ln->dn_list);
+ ln = ln->dn_list;
+ }
+ }
+ break;
+
+ case DT_NODE_OP3:
+ dt_sugar_visit_all(dp, dnp->dn_expr);
+ dt_sugar_visit_all(dp, dnp->dn_left);
+ dt_sugar_visit_all(dp, dnp->dn_right);
+ break;
+
+ case DT_NODE_DEXPR:
+ case DT_NODE_DFUNC:
+ dt_sugar_visit_all(dp, dnp->dn_expr);
+ break;
+
+ case DT_NODE_AGG:
+ for (arg = dnp->dn_aggtup; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+
+ if (dnp->dn_aggfun)
+ dt_sugar_visit_all(dp, dnp->dn_aggfun);
+ break;
+
+ case DT_NODE_CLAUSE:
+ for (arg = dnp->dn_pdescs; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+
+ if (dnp->dn_pred != NULL)
+ dt_sugar_visit_all(dp, dnp->dn_pred);
+
+ for (arg = dnp->dn_acts; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+ break;
+
+ case DT_NODE_INLINE: {
+ const dt_idnode_t *inp = dnp->dn_ident->di_iarg;
+
+ dt_sugar_visit_all(dp, inp->din_root);
+ break;
+ }
+ case DT_NODE_MEMBER:
+ if (dnp->dn_membexpr)
+ dt_sugar_visit_all(dp, dnp->dn_membexpr);
+ break;
+
+ case DT_NODE_XLATOR:
+ for (arg = dnp->dn_members; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+ break;
+
+ case DT_NODE_PROVIDER:
+ for (arg = dnp->dn_probes; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+ break;
+
+ case DT_NODE_PROG:
+ for (arg = dnp->dn_list; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+ break;
+
+ case DT_NODE_IF:
+ dp->dtsp_num_ifs++;
+ dt_sugar_visit_all(dp, dnp->dn_conditional);
+
+ for (arg = dnp->dn_body; arg != NULL; arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+ for (arg = dnp->dn_alternate_body; arg != NULL;
+ arg = arg->dn_list)
+ dt_sugar_visit_all(dp, arg);
+
+ break;
+
+ default:
+ (void) dnerror(dnp, D_UNKNOWN, "bad node %p, kind %d\n",
+ (void *)dnp, dnp->dn_kind);
+ }
+}
+
+/*
+ * Return a new clause which resets the error variable to zero:
+ *
+ * dp_pdescs{ self->%error = 0; }
+ *
+ * This clause will be executed at the beginning of each meta-clause, to
+ * ensure the error variable is unset (in case the previous meta-clause
+ * failed).
+ */
+static dt_node_t *
+dt_sugar_new_clearerror_clause(dt_sugar_parse_t *dp)
+{
+ dt_node_t *stmt = dt_node_statement(dt_node_op2(DT_TOK_ASGN,
+ dt_sugar_new_error_var(), dt_node_int(0)));
+ return (dt_node_clause(dp->dtsp_pdescs, NULL, stmt));
+}
+
+/*
+ * Evaluate the conditional, and recursively visit the body of the "if"
+ * statement (and the "else", if present).
+ */
+static void
+dt_sugar_do_if(dt_sugar_parse_t *dp, dt_node_t *if_stmt, int precondition)
+{
+ int newid;
+
+ assert(if_stmt->dn_kind == DT_NODE_IF);
+
+ /* condition */
+ newid = dt_sugar_new_condition(dp,
+ if_stmt->dn_conditional, precondition);
+
+ /* body of if */
+ dt_sugar_visit_stmts(dp, if_stmt->dn_body, newid);
+
+ /*
+ * Visit the body of the "else" statement, if present. Note that we
+ * generate a new condition which is the inverse of the previous
+ * condition.
+ */
+ if (if_stmt->dn_alternate_body != NULL) {
+ dt_node_t *pred =
+ dt_node_op1(DT_TOK_LNEG, dt_sugar_new_condition_var(newid));
+ dt_sugar_visit_stmts(dp, if_stmt->dn_alternate_body,
+ dt_sugar_new_condition(dp, pred, precondition));
+ }
+}
+
+/*
+ * Generate a new clause to evaluate the statements based on the condition.
+ * The new clause will be appended to dp_first_new_clause.
+ *
+ * dp_pdescs
+ * /!self->%error && this->%condition_<condid>/
+ * {
+ * stmts
+ * }
+ */
+static void
+dt_sugar_new_basic_block(dt_sugar_parse_t *dp, int condid, dt_node_t *stmts)
+{
+ dt_node_t *pred = NULL;
+
+ if (condid == 0) {
+ /*
+ * Don't bother with !error on the first clause, because if
+ * there is only one clause, we don't add the prelude to
+ * zero out %error.
+ */
+ if (dp->dtsp_num_conditions != 0) {
+ pred = dt_node_op1(DT_TOK_LNEG,
+ dt_sugar_new_error_var());
+ }
+ } else {
+ pred = dt_node_op2(DT_TOK_LAND,
+ dt_node_op1(DT_TOK_LNEG, dt_sugar_new_error_var()),
+ dt_sugar_new_condition_var(condid));
+ }
+ dt_sugar_append_clause(dp,
+ dt_node_clause(dp->dtsp_pdescs, pred, stmts));
+}
+
+/*
+ * Visit all the statements in this list, and break them into basic blocks,
+ * generating new clauses for "if" and "else" statements.
+ */
+static void
+dt_sugar_visit_stmts(dt_sugar_parse_t *dp, dt_node_t *stmts, int precondition)
+{
+ dt_node_t *stmt;
+ dt_node_t *prev_stmt = NULL;
+ dt_node_t *next_stmt;
+ dt_node_t *first_stmt_in_basic_block = NULL;
+
+ for (stmt = stmts; stmt != NULL; stmt = next_stmt) {
+ next_stmt = stmt->dn_list;
+
+ if (stmt->dn_kind != DT_NODE_IF) {
+ if (first_stmt_in_basic_block == NULL)
+ first_stmt_in_basic_block = stmt;
+ prev_stmt = stmt;
+ continue;
+ }
+
+ /*
+ * Remove this and following statements from the previous
+ * clause.
+ */
+ if (prev_stmt != NULL)
+ prev_stmt->dn_list = NULL;
+
+ /*
+ * Generate clause for statements preceding the "if"
+ */
+ if (first_stmt_in_basic_block != NULL) {
+ dt_sugar_new_basic_block(dp, precondition,
+ first_stmt_in_basic_block);
+ }
+
+ dt_sugar_do_if(dp, stmt, precondition);
+
+ first_stmt_in_basic_block = NULL;
+
+ prev_stmt = stmt;
+ }
+
+ /* generate clause for statements after last "if". */
+ if (first_stmt_in_basic_block != NULL) {
+ dt_sugar_new_basic_block(dp, precondition,
+ first_stmt_in_basic_block);
+ }
+}
+
+/*
+ * Generate a new clause which will set the error variable when an error occurs.
+ * Only one of these clauses is created per program (e.g. script file).
+ * The clause is:
+ *
+ * dtrace:::ERROR{ self->%error = 1; }
+ */
+static dt_node_t *
+dt_sugar_makeerrorclause(void)
+{
+ dt_node_t *acts, *pdesc;
+
+ pdesc = dt_node_pdesc_by_name(strdup("dtrace:::ERROR"));
+
+ acts = dt_node_statement(dt_node_op2(DT_TOK_ASGN,
+ dt_sugar_new_error_var(), dt_node_int(1)));
+
+ return (dt_node_clause(pdesc, NULL, acts));
+}
+
+/*
+ * Transform the super-clause into straight-D, returning the new list of
+ * sub-clauses.
+ */
+dt_node_t *
+dt_compile_sugar(dtrace_hdl_t *dtp, dt_node_t *clause)
+{
+ dt_sugar_parse_t dp = { 0 };
+ int condid = 0;
+
+ dp.dtsp_dtp = dtp;
+ dp.dtsp_pdescs = clause->dn_pdescs;
+
+ /* make dt_node_int() generate an "int"-typed integer */
+ yyintdecimal = B_TRUE;
+ yyintsuffix[0] = '\0';
+ yyintprefix = 0;
+
+ dt_sugar_visit_all(&dp, clause);
+
+ if (dp.dtsp_num_ifs == 0 && dp.dtsp_num_conditions == 0) {
+ /*
+ * There is nothing that modifies the number of clauses. Use
+ * the existing clause as-is, with its predicate intact. This
+ * ensures that in the absence of D sugar, the body of the
+ * clause can create a variable that is referenced in the
+ * predicate.
+ */
+ dt_sugar_append_clause(&dp, dt_node_clause(clause->dn_pdescs,
+ clause->dn_pred, clause->dn_acts));
+ } else {
+ if (clause->dn_pred != NULL) {
+ condid = dt_sugar_new_condition(&dp,
+ clause->dn_pred, condid);
+ }
+
+ if (clause->dn_acts == NULL) {
+ /*
+ * dt_sugar_visit_stmts() does not emit a clause with
+ * an empty body (e.g. if there's an empty "if" body),
+ * but we need the empty body here so that we
+ * continue to get the default tracing action.
+ */
+ dt_sugar_new_basic_block(&dp, condid, NULL);
+ } else {
+ dt_sugar_visit_stmts(&dp, clause->dn_acts, condid);
+ }
+ }
+
+ if (dp.dtsp_num_conditions != 0) {
+ dt_sugar_prepend_clause(&dp,
+ dt_sugar_new_clearerror_clause(&dp));
+ }
+
+ if (dp.dtsp_clause_list != NULL &&
+ dp.dtsp_clause_list->dn_list != NULL && !dtp->dt_has_sugar) {
+ dtp->dt_has_sugar = B_TRUE;
+ dt_sugar_prepend_clause(&dp, dt_sugar_makeerrorclause());
+ }
+ return (dp.dtsp_clause_list);
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h
index f0088a939cb0..f0bc83a7fc7b 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h
@@ -25,7 +25,7 @@
*/
/*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
@@ -59,6 +59,7 @@ extern "C" {
#define DTRACE_VERSION 3 /* library ABI interface version */
struct ps_prochandle;
+struct dt_node;
typedef struct dtrace_hdl dtrace_hdl_t;
typedef struct dtrace_prog dtrace_prog_t;
typedef struct dtrace_vector dtrace_vector_t;
@@ -115,7 +116,7 @@ typedef struct dtrace_proginfo {
#define DTRACE_C_CPP 0x0010 /* Preprocess input file with cpp(1) utility */
#define DTRACE_C_KNODEF 0x0020 /* Permit unresolved kernel symbols in DIFO */
#define DTRACE_C_UNODEF 0x0040 /* Permit unresolved user symbols in DIFO */
-#define DTRACE_C_PSPEC 0x0080 /* Intepret ambiguous specifiers as probes */
+#define DTRACE_C_PSPEC 0x0080 /* Interpret ambiguous specifiers as probes */
#define DTRACE_C_ETAGS 0x0100 /* Prefix error messages with error tags */
#define DTRACE_C_ARGREF 0x0200 /* Do not require all macro args to be used */
#define DTRACE_C_DEFARG 0x0800 /* Use 0/"" as value for unspecified args */
@@ -523,6 +524,10 @@ extern int dtrace_type_strcompile(dtrace_hdl_t *,
extern int dtrace_type_fcompile(dtrace_hdl_t *,
FILE *, dtrace_typeinfo_t *);
+extern struct dt_node *dt_compile_sugar(dtrace_hdl_t *,
+ struct dt_node *);
+
+
/*
* DTrace Probe Interface
*
diff --git a/cddl/lib/libdtrace/Makefile b/cddl/lib/libdtrace/Makefile
index 080865c44bab..83a93cf0cb50 100644
--- a/cddl/lib/libdtrace/Makefile
+++ b/cddl/lib/libdtrace/Makefile
@@ -42,6 +42,7 @@ SRCS= dt_aggregate.c \
dt_string.c \
dt_strtab.c \
dt_subr.c \
+ dt_sugar.c \
dt_work.c \
dt_xlator.c \
gmatch.c