From owner-svn-src-head@freebsd.org Tue Aug 16 02:30:21 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id A3570BBA2CC; Tue, 16 Aug 2016 02:30:21 +0000 (UTC) (envelope-from markj@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 6DF511304; Tue, 16 Aug 2016 02:30:21 +0000 (UTC) (envelope-from markj@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u7G2UKBY055175; Tue, 16 Aug 2016 02:30:20 GMT (envelope-from markj@FreeBSD.org) Received: (from markj@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u7G2UKBQ055166; Tue, 16 Aug 2016 02:30:20 GMT (envelope-from markj@FreeBSD.org) Message-Id: <201608160230.u7G2UKBQ055166@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: markj set sender to markj@FreeBSD.org using -f From: Mark Johnston Date: Tue, 16 Aug 2016 02:30:20 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r304200 - in head/cddl: contrib/opensolaris/cmd/dtrace/test/cmd/scripts contrib/opensolaris/cmd/dtrace/test/tst/common/sugar contrib/opensolaris/lib/libdtrace/common lib/libdtrace X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 16 Aug 2016 02:30:21 -0000 Author: markj Date: Tue Aug 16 02:30:19 2016 New Revision: 304200 URL: https://svnweb.freebsd.org/changeset/base/304200 Log: MFV r304057: 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 Reviewed by: Sebastien Roy Reviewed by: Paul Dagnelie Reviewed by: Bryan Cantrill Approved by: Richard Lowe Author: Matthew Ahrens MFC after: 2 weeks Relnotes: yes Added: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sugar/ - copied from r304057, vendor/illumos/dist/cmd/dtrace/test/tst/common/sugar/ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c - copied unchanged from r304057, vendor/illumos/dist/lib/libdtrace/common/dt_sugar.c Modified: head/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dstyle.pl head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h head/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h head/cddl/lib/libdtrace/Makefile Directory Properties: head/cddl/contrib/opensolaris/ (props changed) Modified: head/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dstyle.pl ============================================================================== --- head/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dstyle.pl Tue Aug 16 02:25:19 2016 (r304199) +++ head/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/scripts/dstyle.pl Tue Aug 16 02:30:19 2016 (r304200) @@ -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"; } Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c ============================================================================== --- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c Tue Aug 16 02:25:19 2016 (r304199) +++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c Tue Aug 16 02:30:19 2016 (r304200) @@ -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_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) @@ -2519,6 +2518,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 @@ -2538,6 +2559,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: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y ============================================================================== --- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y Tue Aug 16 02:25:19 2016 (r304199) +++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y Tue Aug 16 02:30:19 2016 (r304200) @@ -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 probe_specifier_list %type probe_specifier %type statement_list +%type statement_list_impl +%type statement_or_block %type statement %type declaration %type 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: Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h ============================================================================== --- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h Tue Aug 16 02:25:19 2016 (r304199) +++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h Tue Aug 16 02:30:19 2016 (r304200) @@ -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? */ }; /* Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c ============================================================================== --- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c Tue Aug 16 02:25:19 2016 (r304199) +++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c Tue Aug 16 02:30:19 2016 (r304200) @@ -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 @@ -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 }; Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c ============================================================================== --- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c Tue Aug 16 02:25:19 2016 (r304199) +++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c Tue Aug 16 02:30:19 2016 (r304200) @@ -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_nod 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 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: @@ -3218,10 +3229,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) { @@ -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_ 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 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; @@ -4619,6 +4624,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) { @@ -4729,6 +4909,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: @@ -4790,6 +4977,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: @@ -4840,6 +5028,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, "\n", (void *)dnp, dnp->dn_kind); Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h ============================================================================== --- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h Tue Aug 16 02:25:19 2016 (r304199) +++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h Tue Aug 16 02:30:19 2016 (r304200) @@ -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 *); Copied: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c (from r304057, vendor/illumos/dist/lib/libdtrace/common/dt_sugar.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c Tue Aug 16 02:30:19 2016 (r304200, copy of r304057, vendor/illumos/dist/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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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_", 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_ = + * (this->%condition_ && 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 , 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_ && pred) */ + value = dt_node_op2(DT_TOK_LAND, + dt_sugar_new_condition_var(condid), pred); + } + + /* body is "this->%condition_ = ;" */ + 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. + */ *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***