Author: markj
Date: Sat Aug 13 19:57:36 2016
New Revision: 304057
URL: https://svnweb.freebsd.org/changeset/base/304057

Log:
  7085 add support for "if" and "else" statements in dtrace
  
  illumos/illumos-gate@c3bd3abd8856e8e75d820f65c58031cd6cbac818
  
  Add syntactic sugar to dtrace: "if" and "else" statements. The sugar is
  baked down to standard dtrace features by adding additional clauses with
  the appropriate predicates.
  
  Reviewed by: Adam Leventhal <a...@delphix.com>
  Reviewed by: Sebastien Roy <sebastien....@delphix.com>
  Reviewed by: Paul Dagnelie <p...@delphix.com>
  Reviewed by: Bryan Cantrill <br...@joyent.com>
  Approved by: Richard Lowe <richl...@richlowe.net>
  Author: Matthew Ahrens <mahr...@delphix.com>

Added:
  vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/
  vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.else.d
  vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if.d
  vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if2.d
  vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if_before_after.d
  vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if_nested.d
  
vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon.d
  
vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon2.d
  vendor/illumos/dist/lib/libdtrace/common/dt_sugar.c
Modified:
  vendor/illumos/dist/cmd/dtrace/test/cmd/scripts/dstyle.pl
  vendor/illumos/dist/lib/libdtrace/common/dt_cc.c
  vendor/illumos/dist/lib/libdtrace/common/dt_grammar.y
  vendor/illumos/dist/lib/libdtrace/common/dt_impl.h
  vendor/illumos/dist/lib/libdtrace/common/dt_open.c
  vendor/illumos/dist/lib/libdtrace/common/dt_parser.c
  vendor/illumos/dist/lib/libdtrace/common/dt_parser.h
  vendor/illumos/dist/lib/libdtrace/common/dtrace.h

Modified: vendor/illumos/dist/cmd/dtrace/test/cmd/scripts/dstyle.pl
==============================================================================
--- vendor/illumos/dist/cmd/dtrace/test/cmd/scripts/dstyle.pl   Sat Aug 13 
19:54:32 2016        (r304056)
+++ vendor/illumos/dist/cmd/dtrace/test/cmd/scripts/dstyle.pl   Sat Aug 13 
19:57:36 2016        (r304057)
@@ -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";
                        }

Added: vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.else.d
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.else.d     Sat Aug 
13 19:57:36 2016        (r304057)
@@ -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)
+}

Added: vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if.d
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if.d       Sat Aug 
13 19:57:36 2016        (r304057)
@@ -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)
+}

Added: vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if2.d
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if2.d      Sat Aug 
13 19:57:36 2016        (r304057)
@@ -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)
+}

Added: 
vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if_before_after.d
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if_before_after.d  
Sat Aug 13 19:57:36 2016        (r304057)
@@ -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);
+}

Added: vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if_nested.d
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if_nested.d        
Sat Aug 13 19:57:36 2016        (r304057)
@@ -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);
+}

Added: 
vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon.d
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ 
vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon.d
    Sat Aug 13 19:57:36 2016        (r304057)
@@ -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)
+       }
+}

Added: 
vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon2.d
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ 
vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/tst.if_trailing_semicolon2.d
   Sat Aug 13 19:57:36 2016        (r304057)
@@ -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)
+       }
+}

Modified: vendor/illumos/dist/lib/libdtrace/common/dt_cc.c
==============================================================================
--- vendor/illumos/dist/lib/libdtrace/common/dt_cc.c    Sat Aug 13 19:54:32 
2016        (r304056)
+++ vendor/illumos/dist/lib/libdtrace/common/dt_cc.c    Sat Aug 13 19:57:36 
2016        (r304057)
@@ -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
  */
 
@@ -119,7 +119,6 @@ static const dtrace_diftype_t dt_int_rty
 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)
@@ -2419,6 +2418,28 @@ dt_compile(dtrace_hdl_t *dtp, int contex
        }
 
        /*
+        * 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
@@ -2438,6 +2459,8 @@ dt_compile(dtrace_hdl_t *dtp, int contex
                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:

Modified: vendor/illumos/dist/lib/libdtrace/common/dt_grammar.y
==============================================================================
--- vendor/illumos/dist/lib/libdtrace/common/dt_grammar.y       Sat Aug 13 
19:54:32 2016        (r304056)
+++ vendor/illumos/dist/lib/libdtrace/common/dt_grammar.y       Sat Aug 13 
19:57:36 2016        (r304057)
@@ -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
@@ -317,9 +320,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 "
@@ -328,6 +333,7 @@ probe_definition:
        |       probe_specifiers DT_TOK_DIV expression DT_TOK_EPRED
                    '{' statement_list '}' {
                        $$ = dt_node_clause($1, $3, $6);
+                       yybegin(YYS_CLAUSE);
                }
        ;
 
@@ -347,12 +353,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:

Modified: vendor/illumos/dist/lib/libdtrace/common/dt_impl.h
==============================================================================
--- vendor/illumos/dist/lib/libdtrace/common/dt_impl.h  Sat Aug 13 19:54:32 
2016        (r304056)
+++ vendor/illumos/dist/lib/libdtrace/common/dt_impl.h  Sat Aug 13 19:57:36 
2016        (r304057)
@@ -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
@@ -320,6 +320,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? */
 };
 
 /*

Modified: vendor/illumos/dist/lib/libdtrace/common/dt_open.c
==============================================================================
--- vendor/illumos/dist/lib/libdtrace/common/dt_open.c  Sat Aug 13 19:54:32 
2016        (r304056)
+++ vendor/illumos/dist/lib/libdtrace/common/dt_open.c  Sat Aug 13 19:57:36 
2016        (r304057)
@@ -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>
@@ -115,8 +115,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 */
@@ -142,6 +143,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
 };
 

Modified: vendor/illumos/dist/lib/libdtrace/common/dt_parser.c
==============================================================================
--- vendor/illumos/dist/lib/libdtrace/common/dt_parser.c        Sat Aug 13 
19:54:32 2016        (r304056)
+++ vendor/illumos/dist/lib/libdtrace/common/dt_parser.c        Sat Aug 13 
19:57:36 2016        (r304057)
@@ -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) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
  */
 
 /*
@@ -2137,6 +2137,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;
@@ -2205,7 +2216,6 @@ dt_node_clause(dt_node_t *pdescs, dt_nod
        dnp->dn_pred = pred;
        dnp->dn_acts = acts;
 
-       yybegin(YYS_CLAUSE);
        return (dnp);
 }
 
@@ -3197,8 +3207,9 @@ dt_cook_op2(dt_node_t *dnp, uint_t idfla
                                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:
@@ -3212,10 +3223,12 @@ dt_cook_op2(dt_node_t *dnp, uint_t idfla
                        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) {
@@ -3639,45 +3652,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);
 
@@ -4496,7 +4498,8 @@ static dt_node_t *(*dt_cook_funcs[])(dt_
        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 */
 };
 
 /*
@@ -4511,6 +4514,8 @@ dt_node_cook(dt_node_t *dnp, uint_t idfl
 
        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;
 
@@ -4613,6 +4618,181 @@ dt_node_diftype(dtrace_hdl_t *dtp, const
        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)
 {
@@ -4723,6 +4903,13 @@ dt_node_printr(dt_node_t *dnp, FILE *fp,
                (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:
@@ -4784,6 +4971,7 @@ dt_node_printr(dt_node_t *dnp, FILE *fp,
 
                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:
@@ -4834,6 +5022,24 @@ dt_node_printr(dt_node_t *dnp, FILE *fp,
                        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);

Modified: vendor/illumos/dist/lib/libdtrace/common/dt_parser.h
==============================================================================
--- vendor/illumos/dist/lib/libdtrace/common/dt_parser.h        Sat Aug 13 
19:54:32 2016        (r304056)
+++ vendor/illumos/dist/lib/libdtrace/common/dt_parser.h        Sat Aug 13 
19:57:36 2016        (r304057)
@@ -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
 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 *,
 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 *);
 

Added: vendor/illumos/dist/lib/libdtrace/common/dt_sugar.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ vendor/illumos/dist/lib/libdtrace/common/dt_sugar.c Sat Aug 13 19:57:36 
2016        (r304057)
@@ -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 *

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to