xref: /titanic_52/usr/src/lib/libdtrace/common/dt_sugar.c (revision 0af8f00bde7c34464aa603d30c5cd6d988b857d2)
1*0af8f00bSMatthew Ahrens /*
2*0af8f00bSMatthew Ahrens  * CDDL HEADER START
3*0af8f00bSMatthew Ahrens  *
4*0af8f00bSMatthew Ahrens  * This file and its contents are supplied under the terms of the
5*0af8f00bSMatthew Ahrens  * Common Development and Distribution License ("CDDL"), version 1.0.
6*0af8f00bSMatthew Ahrens  * You may only use this file in accordance with the terms of version
7*0af8f00bSMatthew Ahrens  * 1.0 of the CDDL.
8*0af8f00bSMatthew Ahrens  *
9*0af8f00bSMatthew Ahrens  * A full copy of the text of the CDDL should have accompanied this
10*0af8f00bSMatthew Ahrens  * source.  A copy of the CDDL is also available via the Internet at
11*0af8f00bSMatthew Ahrens  * http://www.illumos.org/license/CDDL.
12*0af8f00bSMatthew Ahrens  *
13*0af8f00bSMatthew Ahrens  * CDDL HEADER END
14*0af8f00bSMatthew Ahrens  */
15*0af8f00bSMatthew Ahrens 
16*0af8f00bSMatthew Ahrens /*
17*0af8f00bSMatthew Ahrens  * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
18*0af8f00bSMatthew Ahrens  */
19*0af8f00bSMatthew Ahrens 
20*0af8f00bSMatthew Ahrens /*
21*0af8f00bSMatthew Ahrens  * Syntactic sugar features are implemented by transforming the D parse tree
22*0af8f00bSMatthew Ahrens  * such that it only uses the subset of D that is supported by the rest of the
23*0af8f00bSMatthew Ahrens  * compiler / the kernel.  A clause containing these language features is
24*0af8f00bSMatthew Ahrens  * referred to as a "super-clause", and its transformation typically entails
25*0af8f00bSMatthew Ahrens  * creating several "sub-clauses" to implement it. For diagnosability, the
26*0af8f00bSMatthew Ahrens  * sub-clauses will be printed if the "-xtree=8" flag is specified.
27*0af8f00bSMatthew Ahrens  *
28*0af8f00bSMatthew Ahrens  * Currently, the only syntactic sugar feature is "if/else" statements.  Each
29*0af8f00bSMatthew Ahrens  * basic block (e.g. the body of the "if" and "else" statements, and the
30*0af8f00bSMatthew Ahrens  * statements before and after) is turned into its own sub-clause, with a
31*0af8f00bSMatthew Ahrens  * predicate that causes it to be executed only if the code flows to this point.
32*0af8f00bSMatthew Ahrens  * Nested if/else statements are supported.
33*0af8f00bSMatthew Ahrens  *
34*0af8f00bSMatthew Ahrens  * This infrastructure is designed to accommodate other syntactic sugar features
35*0af8f00bSMatthew Ahrens  * in the future.
36*0af8f00bSMatthew Ahrens  */
37*0af8f00bSMatthew Ahrens 
38*0af8f00bSMatthew Ahrens #include <sys/types.h>
39*0af8f00bSMatthew Ahrens #include <sys/wait.h>
40*0af8f00bSMatthew Ahrens #include <sys/sysmacros.h>
41*0af8f00bSMatthew Ahrens 
42*0af8f00bSMatthew Ahrens #include <assert.h>
43*0af8f00bSMatthew Ahrens #include <strings.h>
44*0af8f00bSMatthew Ahrens #include <stdlib.h>
45*0af8f00bSMatthew Ahrens #include <stdio.h>
46*0af8f00bSMatthew Ahrens #include <ctype.h>
47*0af8f00bSMatthew Ahrens #include <dt_module.h>
48*0af8f00bSMatthew Ahrens #include <dt_program.h>
49*0af8f00bSMatthew Ahrens #include <dt_provider.h>
50*0af8f00bSMatthew Ahrens #include <dt_printf.h>
51*0af8f00bSMatthew Ahrens #include <dt_pid.h>
52*0af8f00bSMatthew Ahrens #include <dt_grammar.h>
53*0af8f00bSMatthew Ahrens #include <dt_ident.h>
54*0af8f00bSMatthew Ahrens #include <dt_string.h>
55*0af8f00bSMatthew Ahrens #include <dt_impl.h>
56*0af8f00bSMatthew Ahrens 
57*0af8f00bSMatthew Ahrens typedef struct dt_sugar_parse {
58*0af8f00bSMatthew Ahrens 	dtrace_hdl_t *dtsp_dtp;		/* dtrace handle */
59*0af8f00bSMatthew Ahrens 	dt_node_t *dtsp_pdescs;		/* probe descriptions */
60*0af8f00bSMatthew Ahrens 	int dtsp_num_conditions;	/* number of condition variables */
61*0af8f00bSMatthew Ahrens 	int dtsp_num_ifs;		/* number of "if" statements */
62*0af8f00bSMatthew Ahrens 	dt_node_t *dtsp_clause_list;	/* list of clauses */
63*0af8f00bSMatthew Ahrens } dt_sugar_parse_t;
64*0af8f00bSMatthew Ahrens 
65*0af8f00bSMatthew Ahrens static void dt_sugar_visit_stmts(dt_sugar_parse_t *, dt_node_t *, int);
66*0af8f00bSMatthew Ahrens 
67*0af8f00bSMatthew Ahrens /*
68*0af8f00bSMatthew Ahrens  * Return a node for "self->%error".
69*0af8f00bSMatthew Ahrens  *
70*0af8f00bSMatthew Ahrens  * Note that the "%" is part of the variable name, and is included so that
71*0af8f00bSMatthew Ahrens  * this variable name can not collide with any user-specified variable.
72*0af8f00bSMatthew Ahrens  *
73*0af8f00bSMatthew Ahrens  * This error variable is used to keep track of if there has been an error
74*0af8f00bSMatthew Ahrens  * in any of the sub-clauses, and is used to prevent execution of subsequent
75*0af8f00bSMatthew Ahrens  * sub-clauses following an error.
76*0af8f00bSMatthew Ahrens  */
77*0af8f00bSMatthew Ahrens static dt_node_t *
78*0af8f00bSMatthew Ahrens dt_sugar_new_error_var(void)
79*0af8f00bSMatthew Ahrens {
80*0af8f00bSMatthew Ahrens 	return (dt_node_op2(DT_TOK_PTR, dt_node_ident(strdup("self")),
81*0af8f00bSMatthew Ahrens 	    dt_node_ident(strdup("%error"))));
82*0af8f00bSMatthew Ahrens }
83*0af8f00bSMatthew Ahrens 
84*0af8f00bSMatthew Ahrens /*
85*0af8f00bSMatthew Ahrens  * Append this clause to the clause list.
86*0af8f00bSMatthew Ahrens  */
87*0af8f00bSMatthew Ahrens static void
88*0af8f00bSMatthew Ahrens dt_sugar_append_clause(dt_sugar_parse_t *dp, dt_node_t *clause)
89*0af8f00bSMatthew Ahrens {
90*0af8f00bSMatthew Ahrens 	dp->dtsp_clause_list = dt_node_link(dp->dtsp_clause_list, clause);
91*0af8f00bSMatthew Ahrens }
92*0af8f00bSMatthew Ahrens 
93*0af8f00bSMatthew Ahrens /*
94*0af8f00bSMatthew Ahrens  * Prepend this clause to the clause list.
95*0af8f00bSMatthew Ahrens  */
96*0af8f00bSMatthew Ahrens static void
97*0af8f00bSMatthew Ahrens dt_sugar_prepend_clause(dt_sugar_parse_t *dp, dt_node_t *clause)
98*0af8f00bSMatthew Ahrens {
99*0af8f00bSMatthew Ahrens 	dp->dtsp_clause_list = dt_node_link(clause, dp->dtsp_clause_list);
100*0af8f00bSMatthew Ahrens }
101*0af8f00bSMatthew Ahrens 
102*0af8f00bSMatthew Ahrens /*
103*0af8f00bSMatthew Ahrens  * Return a node for "this->%condition_<condid>", or NULL if condid==0.
104*0af8f00bSMatthew Ahrens  *
105*0af8f00bSMatthew Ahrens  * Note that the "%" is part of the variable name, and is included so that
106*0af8f00bSMatthew Ahrens  * this variable name can not collide with any user-specified variable.
107*0af8f00bSMatthew Ahrens  */
108*0af8f00bSMatthew Ahrens static dt_node_t *
109*0af8f00bSMatthew Ahrens dt_sugar_new_condition_var(int condid)
110*0af8f00bSMatthew Ahrens {
111*0af8f00bSMatthew Ahrens 	char *str;
112*0af8f00bSMatthew Ahrens 
113*0af8f00bSMatthew Ahrens 	if (condid == 0)
114*0af8f00bSMatthew Ahrens 		return (NULL);
115*0af8f00bSMatthew Ahrens 	assert(condid > 0);
116*0af8f00bSMatthew Ahrens 
117*0af8f00bSMatthew Ahrens 	(void) asprintf(&str, "%%condition_%d", ABS(condid));
118*0af8f00bSMatthew Ahrens 	return (dt_node_op2(DT_TOK_PTR, dt_node_ident(strdup("this")),
119*0af8f00bSMatthew Ahrens 	    dt_node_ident(str)));
120*0af8f00bSMatthew Ahrens }
121*0af8f00bSMatthew Ahrens 
122*0af8f00bSMatthew Ahrens /*
123*0af8f00bSMatthew Ahrens  * Return new clause to evaluate predicate and set newcond.  condid is
124*0af8f00bSMatthew Ahrens  * the condition that we are already under, or 0 if none.
125*0af8f00bSMatthew Ahrens  * The new clause will be of the form:
126*0af8f00bSMatthew Ahrens  *
127*0af8f00bSMatthew Ahrens  * dp_pdescs
128*0af8f00bSMatthew Ahrens  * /!self->%error/
129*0af8f00bSMatthew Ahrens  * {
130*0af8f00bSMatthew Ahrens  *	this->%condition_<newcond> =
131*0af8f00bSMatthew Ahrens  *	    (this->%condition_<condid> && pred);
132*0af8f00bSMatthew Ahrens  * }
133*0af8f00bSMatthew Ahrens  *
134*0af8f00bSMatthew Ahrens  * Note: if condid==0, we will instead do "... = (1 && pred)", to effectively
135*0af8f00bSMatthew Ahrens  * convert the pred to a boolean.
136*0af8f00bSMatthew Ahrens  *
137*0af8f00bSMatthew Ahrens  * Note: Unless an error has been encountered, we always set the condition
138*0af8f00bSMatthew Ahrens  * variable (either to 0 or 1).  This lets us avoid resetting the condition
139*0af8f00bSMatthew Ahrens  * variables back to 0 when the super-clause completes.
140*0af8f00bSMatthew Ahrens  */
141*0af8f00bSMatthew Ahrens static dt_node_t *
142*0af8f00bSMatthew Ahrens dt_sugar_new_condition_impl(dt_sugar_parse_t *dp,
143*0af8f00bSMatthew Ahrens     dt_node_t *pred, int condid, int newcond)
144*0af8f00bSMatthew Ahrens {
145*0af8f00bSMatthew Ahrens 	dt_node_t *value, *body, *newpred;
146*0af8f00bSMatthew Ahrens 
147*0af8f00bSMatthew Ahrens 	/* predicate is !self->%error */
148*0af8f00bSMatthew Ahrens 	newpred = dt_node_op1(DT_TOK_LNEG, dt_sugar_new_error_var());
149*0af8f00bSMatthew Ahrens 
150*0af8f00bSMatthew Ahrens 	if (condid == 0) {
151*0af8f00bSMatthew Ahrens 		/*
152*0af8f00bSMatthew Ahrens 		 * value is (1 && pred)
153*0af8f00bSMatthew Ahrens 		 *
154*0af8f00bSMatthew Ahrens 		 * Note, D doesn't allow a probe-local "this" variable to
155*0af8f00bSMatthew Ahrens 		 * be reused as a different type, even from a different probe.
156*0af8f00bSMatthew Ahrens 		 * Therefore, value can't simply be <pred>, because then
157*0af8f00bSMatthew Ahrens 		 * its type could be different when we reuse this condid
158*0af8f00bSMatthew Ahrens 		 * in a different meta-clause.
159*0af8f00bSMatthew Ahrens 		 */
160*0af8f00bSMatthew Ahrens 		value = dt_node_op2(DT_TOK_LAND, dt_node_int(1), pred);
161*0af8f00bSMatthew Ahrens 	} else {
162*0af8f00bSMatthew Ahrens 		/* value is (this->%condition_<condid> && pred) */
163*0af8f00bSMatthew Ahrens 		value = dt_node_op2(DT_TOK_LAND,
164*0af8f00bSMatthew Ahrens 		    dt_sugar_new_condition_var(condid), pred);
165*0af8f00bSMatthew Ahrens 	}
166*0af8f00bSMatthew Ahrens 
167*0af8f00bSMatthew Ahrens 	/* body is "this->%condition_<retval> = <value>;" */
168*0af8f00bSMatthew Ahrens 	body = dt_node_statement(dt_node_op2(DT_TOK_ASGN,
169*0af8f00bSMatthew Ahrens 	    dt_sugar_new_condition_var(newcond), value));
170*0af8f00bSMatthew Ahrens 
171*0af8f00bSMatthew Ahrens 	return (dt_node_clause(dp->dtsp_pdescs, newpred, body));
172*0af8f00bSMatthew Ahrens }
173*0af8f00bSMatthew Ahrens 
174*0af8f00bSMatthew Ahrens /*
175*0af8f00bSMatthew Ahrens  * Generate a new clause to evaluate predicate and set a new condition variable,
176*0af8f00bSMatthew Ahrens  * whose ID will be returned.  The new clause will be appended to
177*0af8f00bSMatthew Ahrens  * dp_first_new_clause.
178*0af8f00bSMatthew Ahrens  */
179*0af8f00bSMatthew Ahrens static int
180*0af8f00bSMatthew Ahrens dt_sugar_new_condition(dt_sugar_parse_t *dp, dt_node_t *pred, int condid)
181*0af8f00bSMatthew Ahrens {
182*0af8f00bSMatthew Ahrens 	dp->dtsp_num_conditions++;
183*0af8f00bSMatthew Ahrens 	dt_sugar_append_clause(dp, dt_sugar_new_condition_impl(dp,
184*0af8f00bSMatthew Ahrens 	    pred, condid, dp->dtsp_num_conditions));
185*0af8f00bSMatthew Ahrens 	return (dp->dtsp_num_conditions);
186*0af8f00bSMatthew Ahrens }
187*0af8f00bSMatthew Ahrens 
188*0af8f00bSMatthew Ahrens /*
189*0af8f00bSMatthew Ahrens  * Visit the specified node and all of its descendants.  Currently this is only
190*0af8f00bSMatthew Ahrens  * used to count the number of "if" statements (dtsp_num_ifs).
191*0af8f00bSMatthew Ahrens  */
192*0af8f00bSMatthew Ahrens static void
193*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dt_sugar_parse_t *dp, dt_node_t *dnp)
194*0af8f00bSMatthew Ahrens {
195*0af8f00bSMatthew Ahrens 	dt_node_t *arg;
196*0af8f00bSMatthew Ahrens 
197*0af8f00bSMatthew Ahrens 	switch (dnp->dn_kind) {
198*0af8f00bSMatthew Ahrens 	case DT_NODE_FREE:
199*0af8f00bSMatthew Ahrens 	case DT_NODE_INT:
200*0af8f00bSMatthew Ahrens 	case DT_NODE_STRING:
201*0af8f00bSMatthew Ahrens 	case DT_NODE_SYM:
202*0af8f00bSMatthew Ahrens 	case DT_NODE_TYPE:
203*0af8f00bSMatthew Ahrens 	case DT_NODE_PROBE:
204*0af8f00bSMatthew Ahrens 	case DT_NODE_PDESC:
205*0af8f00bSMatthew Ahrens 	case DT_NODE_IDENT:
206*0af8f00bSMatthew Ahrens 		break;
207*0af8f00bSMatthew Ahrens 
208*0af8f00bSMatthew Ahrens 	case DT_NODE_FUNC:
209*0af8f00bSMatthew Ahrens 		for (arg = dnp->dn_args; arg != NULL; arg = arg->dn_list)
210*0af8f00bSMatthew Ahrens 			dt_sugar_visit_all(dp, arg);
211*0af8f00bSMatthew Ahrens 		break;
212*0af8f00bSMatthew Ahrens 
213*0af8f00bSMatthew Ahrens 	case DT_NODE_OP1:
214*0af8f00bSMatthew Ahrens 		dt_sugar_visit_all(dp, dnp->dn_child);
215*0af8f00bSMatthew Ahrens 		break;
216*0af8f00bSMatthew Ahrens 
217*0af8f00bSMatthew Ahrens 	case DT_NODE_OP2:
218*0af8f00bSMatthew Ahrens 		dt_sugar_visit_all(dp, dnp->dn_left);
219*0af8f00bSMatthew Ahrens 		dt_sugar_visit_all(dp, dnp->dn_right);
220*0af8f00bSMatthew Ahrens 		if (dnp->dn_op == DT_TOK_LBRAC) {
221*0af8f00bSMatthew Ahrens 			dt_node_t *ln = dnp->dn_right;
222*0af8f00bSMatthew Ahrens 			while (ln->dn_list != NULL) {
223*0af8f00bSMatthew Ahrens 				dt_sugar_visit_all(dp, ln->dn_list);
224*0af8f00bSMatthew Ahrens 				ln = ln->dn_list;
225*0af8f00bSMatthew Ahrens 			}
226*0af8f00bSMatthew Ahrens 		}
227*0af8f00bSMatthew Ahrens 		break;
228*0af8f00bSMatthew Ahrens 
229*0af8f00bSMatthew Ahrens 	case DT_NODE_OP3:
230*0af8f00bSMatthew Ahrens 		dt_sugar_visit_all(dp, dnp->dn_expr);
231*0af8f00bSMatthew Ahrens 		dt_sugar_visit_all(dp, dnp->dn_left);
232*0af8f00bSMatthew Ahrens 		dt_sugar_visit_all(dp, dnp->dn_right);
233*0af8f00bSMatthew Ahrens 		break;
234*0af8f00bSMatthew Ahrens 
235*0af8f00bSMatthew Ahrens 	case DT_NODE_DEXPR:
236*0af8f00bSMatthew Ahrens 	case DT_NODE_DFUNC:
237*0af8f00bSMatthew Ahrens 		dt_sugar_visit_all(dp, dnp->dn_expr);
238*0af8f00bSMatthew Ahrens 		break;
239*0af8f00bSMatthew Ahrens 
240*0af8f00bSMatthew Ahrens 	case DT_NODE_AGG:
241*0af8f00bSMatthew Ahrens 		for (arg = dnp->dn_aggtup; arg != NULL; arg = arg->dn_list)
242*0af8f00bSMatthew Ahrens 			dt_sugar_visit_all(dp, arg);
243*0af8f00bSMatthew Ahrens 
244*0af8f00bSMatthew Ahrens 		if (dnp->dn_aggfun)
245*0af8f00bSMatthew Ahrens 			dt_sugar_visit_all(dp, dnp->dn_aggfun);
246*0af8f00bSMatthew Ahrens 		break;
247*0af8f00bSMatthew Ahrens 
248*0af8f00bSMatthew Ahrens 	case DT_NODE_CLAUSE:
249*0af8f00bSMatthew Ahrens 		for (arg = dnp->dn_pdescs; arg != NULL; arg = arg->dn_list)
250*0af8f00bSMatthew Ahrens 			dt_sugar_visit_all(dp, arg);
251*0af8f00bSMatthew Ahrens 
252*0af8f00bSMatthew Ahrens 		if (dnp->dn_pred != NULL)
253*0af8f00bSMatthew Ahrens 			dt_sugar_visit_all(dp, dnp->dn_pred);
254*0af8f00bSMatthew Ahrens 
255*0af8f00bSMatthew Ahrens 		for (arg = dnp->dn_acts; arg != NULL; arg = arg->dn_list)
256*0af8f00bSMatthew Ahrens 			dt_sugar_visit_all(dp, arg);
257*0af8f00bSMatthew Ahrens 		break;
258*0af8f00bSMatthew Ahrens 
259*0af8f00bSMatthew Ahrens 	case DT_NODE_INLINE: {
260*0af8f00bSMatthew Ahrens 		const dt_idnode_t *inp = dnp->dn_ident->di_iarg;
261*0af8f00bSMatthew Ahrens 
262*0af8f00bSMatthew Ahrens 		dt_sugar_visit_all(dp, inp->din_root);
263*0af8f00bSMatthew Ahrens 		break;
264*0af8f00bSMatthew Ahrens 	}
265*0af8f00bSMatthew Ahrens 	case DT_NODE_MEMBER:
266*0af8f00bSMatthew Ahrens 		if (dnp->dn_membexpr)
267*0af8f00bSMatthew Ahrens 			dt_sugar_visit_all(dp, dnp->dn_membexpr);
268*0af8f00bSMatthew Ahrens 		break;
269*0af8f00bSMatthew Ahrens 
270*0af8f00bSMatthew Ahrens 	case DT_NODE_XLATOR:
271*0af8f00bSMatthew Ahrens 		for (arg = dnp->dn_members; arg != NULL; arg = arg->dn_list)
272*0af8f00bSMatthew Ahrens 			dt_sugar_visit_all(dp, arg);
273*0af8f00bSMatthew Ahrens 		break;
274*0af8f00bSMatthew Ahrens 
275*0af8f00bSMatthew Ahrens 	case DT_NODE_PROVIDER:
276*0af8f00bSMatthew Ahrens 		for (arg = dnp->dn_probes; arg != NULL; arg = arg->dn_list)
277*0af8f00bSMatthew Ahrens 			dt_sugar_visit_all(dp, arg);
278*0af8f00bSMatthew Ahrens 		break;
279*0af8f00bSMatthew Ahrens 
280*0af8f00bSMatthew Ahrens 	case DT_NODE_PROG:
281*0af8f00bSMatthew Ahrens 		for (arg = dnp->dn_list; arg != NULL; arg = arg->dn_list)
282*0af8f00bSMatthew Ahrens 			dt_sugar_visit_all(dp, arg);
283*0af8f00bSMatthew Ahrens 		break;
284*0af8f00bSMatthew Ahrens 
285*0af8f00bSMatthew Ahrens 	case DT_NODE_IF:
286*0af8f00bSMatthew Ahrens 		dp->dtsp_num_ifs++;
287*0af8f00bSMatthew Ahrens 		dt_sugar_visit_all(dp, dnp->dn_conditional);
288*0af8f00bSMatthew Ahrens 
289*0af8f00bSMatthew Ahrens 		for (arg = dnp->dn_body; arg != NULL; arg = arg->dn_list)
290*0af8f00bSMatthew Ahrens 			dt_sugar_visit_all(dp, arg);
291*0af8f00bSMatthew Ahrens 		for (arg = dnp->dn_alternate_body; arg != NULL;
292*0af8f00bSMatthew Ahrens 		    arg = arg->dn_list)
293*0af8f00bSMatthew Ahrens 			dt_sugar_visit_all(dp, arg);
294*0af8f00bSMatthew Ahrens 
295*0af8f00bSMatthew Ahrens 		break;
296*0af8f00bSMatthew Ahrens 
297*0af8f00bSMatthew Ahrens 	default:
298*0af8f00bSMatthew Ahrens 		(void) dnerror(dnp, D_UNKNOWN, "bad node %p, kind %d\n",
299*0af8f00bSMatthew Ahrens 		    (void *)dnp, dnp->dn_kind);
300*0af8f00bSMatthew Ahrens 	}
301*0af8f00bSMatthew Ahrens }
302*0af8f00bSMatthew Ahrens 
303*0af8f00bSMatthew Ahrens /*
304*0af8f00bSMatthew Ahrens  * Return a new clause which resets the error variable to zero:
305*0af8f00bSMatthew Ahrens  *
306*0af8f00bSMatthew Ahrens  *   dp_pdescs{ self->%error = 0; }
307*0af8f00bSMatthew Ahrens  *
308*0af8f00bSMatthew Ahrens  * This clause will be executed at the beginning of each meta-clause, to
309*0af8f00bSMatthew Ahrens  * ensure the error variable is unset (in case the previous meta-clause
310*0af8f00bSMatthew Ahrens  * failed).
311*0af8f00bSMatthew Ahrens  */
312*0af8f00bSMatthew Ahrens static dt_node_t *
313*0af8f00bSMatthew Ahrens dt_sugar_new_clearerror_clause(dt_sugar_parse_t *dp)
314*0af8f00bSMatthew Ahrens {
315*0af8f00bSMatthew Ahrens 	dt_node_t *stmt = dt_node_statement(dt_node_op2(DT_TOK_ASGN,
316*0af8f00bSMatthew Ahrens 	    dt_sugar_new_error_var(), dt_node_int(0)));
317*0af8f00bSMatthew Ahrens 	return (dt_node_clause(dp->dtsp_pdescs, NULL, stmt));
318*0af8f00bSMatthew Ahrens }
319*0af8f00bSMatthew Ahrens 
320*0af8f00bSMatthew Ahrens /*
321*0af8f00bSMatthew Ahrens  * Evaluate the conditional, and recursively visit the body of the "if"
322*0af8f00bSMatthew Ahrens  * statement (and the "else", if present).
323*0af8f00bSMatthew Ahrens  */
324*0af8f00bSMatthew Ahrens static void
325*0af8f00bSMatthew Ahrens dt_sugar_do_if(dt_sugar_parse_t *dp, dt_node_t *if_stmt, int precondition)
326*0af8f00bSMatthew Ahrens {
327*0af8f00bSMatthew Ahrens 	int newid;
328*0af8f00bSMatthew Ahrens 
329*0af8f00bSMatthew Ahrens 	assert(if_stmt->dn_kind == DT_NODE_IF);
330*0af8f00bSMatthew Ahrens 
331*0af8f00bSMatthew Ahrens 	/* condition */
332*0af8f00bSMatthew Ahrens 	newid = dt_sugar_new_condition(dp,
333*0af8f00bSMatthew Ahrens 	    if_stmt->dn_conditional, precondition);
334*0af8f00bSMatthew Ahrens 
335*0af8f00bSMatthew Ahrens 	/* body of if */
336*0af8f00bSMatthew Ahrens 	dt_sugar_visit_stmts(dp, if_stmt->dn_body, newid);
337*0af8f00bSMatthew Ahrens 
338*0af8f00bSMatthew Ahrens 	/*
339*0af8f00bSMatthew Ahrens 	 * Visit the body of the "else" statement, if present.  Note that we
340*0af8f00bSMatthew Ahrens 	 * generate a new condition which is the inverse of the previous
341*0af8f00bSMatthew Ahrens 	 * condition.
342*0af8f00bSMatthew Ahrens 	 */
343*0af8f00bSMatthew Ahrens 	if (if_stmt->dn_alternate_body != NULL) {
344*0af8f00bSMatthew Ahrens 		dt_node_t *pred =
345*0af8f00bSMatthew Ahrens 		    dt_node_op1(DT_TOK_LNEG, dt_sugar_new_condition_var(newid));
346*0af8f00bSMatthew Ahrens 		dt_sugar_visit_stmts(dp, if_stmt->dn_alternate_body,
347*0af8f00bSMatthew Ahrens 		    dt_sugar_new_condition(dp, pred, precondition));
348*0af8f00bSMatthew Ahrens 	}
349*0af8f00bSMatthew Ahrens }
350*0af8f00bSMatthew Ahrens 
351*0af8f00bSMatthew Ahrens /*
352*0af8f00bSMatthew Ahrens  * Generate a new clause to evaluate the statements based on the condition.
353*0af8f00bSMatthew Ahrens  * The new clause will be appended to dp_first_new_clause.
354*0af8f00bSMatthew Ahrens  *
355*0af8f00bSMatthew Ahrens  * dp_pdescs
356*0af8f00bSMatthew Ahrens  * /!self->%error && this->%condition_<condid>/
357*0af8f00bSMatthew Ahrens  * {
358*0af8f00bSMatthew Ahrens  *	stmts
359*0af8f00bSMatthew Ahrens  * }
360*0af8f00bSMatthew Ahrens  */
361*0af8f00bSMatthew Ahrens static void
362*0af8f00bSMatthew Ahrens dt_sugar_new_basic_block(dt_sugar_parse_t *dp, int condid, dt_node_t *stmts)
363*0af8f00bSMatthew Ahrens {
364*0af8f00bSMatthew Ahrens 	dt_node_t *pred = NULL;
365*0af8f00bSMatthew Ahrens 
366*0af8f00bSMatthew Ahrens 	if (condid == 0) {
367*0af8f00bSMatthew Ahrens 		/*
368*0af8f00bSMatthew Ahrens 		 * Don't bother with !error on the first clause, because if
369*0af8f00bSMatthew Ahrens 		 * there is only one clause, we don't add the prelude to
370*0af8f00bSMatthew Ahrens 		 * zero out %error.
371*0af8f00bSMatthew Ahrens 		 */
372*0af8f00bSMatthew Ahrens 		if (dp->dtsp_num_conditions != 0) {
373*0af8f00bSMatthew Ahrens 			pred = dt_node_op1(DT_TOK_LNEG,
374*0af8f00bSMatthew Ahrens 			    dt_sugar_new_error_var());
375*0af8f00bSMatthew Ahrens 		}
376*0af8f00bSMatthew Ahrens 	} else {
377*0af8f00bSMatthew Ahrens 		pred = dt_node_op2(DT_TOK_LAND,
378*0af8f00bSMatthew Ahrens 		    dt_node_op1(DT_TOK_LNEG, dt_sugar_new_error_var()),
379*0af8f00bSMatthew Ahrens 		    dt_sugar_new_condition_var(condid));
380*0af8f00bSMatthew Ahrens 	}
381*0af8f00bSMatthew Ahrens 	dt_sugar_append_clause(dp,
382*0af8f00bSMatthew Ahrens 	    dt_node_clause(dp->dtsp_pdescs, pred, stmts));
383*0af8f00bSMatthew Ahrens }
384*0af8f00bSMatthew Ahrens 
385*0af8f00bSMatthew Ahrens /*
386*0af8f00bSMatthew Ahrens  * Visit all the statements in this list, and break them into basic blocks,
387*0af8f00bSMatthew Ahrens  * generating new clauses for "if" and "else" statements.
388*0af8f00bSMatthew Ahrens  */
389*0af8f00bSMatthew Ahrens static void
390*0af8f00bSMatthew Ahrens dt_sugar_visit_stmts(dt_sugar_parse_t *dp, dt_node_t *stmts, int precondition)
391*0af8f00bSMatthew Ahrens {
392*0af8f00bSMatthew Ahrens 	dt_node_t *stmt;
393*0af8f00bSMatthew Ahrens 	dt_node_t *prev_stmt = NULL;
394*0af8f00bSMatthew Ahrens 	dt_node_t *next_stmt;
395*0af8f00bSMatthew Ahrens 	dt_node_t *first_stmt_in_basic_block = NULL;
396*0af8f00bSMatthew Ahrens 
397*0af8f00bSMatthew Ahrens 	for (stmt = stmts; stmt != NULL; stmt = next_stmt) {
398*0af8f00bSMatthew Ahrens 		next_stmt = stmt->dn_list;
399*0af8f00bSMatthew Ahrens 
400*0af8f00bSMatthew Ahrens 		if (stmt->dn_kind != DT_NODE_IF) {
401*0af8f00bSMatthew Ahrens 			if (first_stmt_in_basic_block == NULL)
402*0af8f00bSMatthew Ahrens 				first_stmt_in_basic_block = stmt;
403*0af8f00bSMatthew Ahrens 			prev_stmt = stmt;
404*0af8f00bSMatthew Ahrens 			continue;
405*0af8f00bSMatthew Ahrens 		}
406*0af8f00bSMatthew Ahrens 
407*0af8f00bSMatthew Ahrens 		/*
408*0af8f00bSMatthew Ahrens 		 * Remove this and following statements from the previous
409*0af8f00bSMatthew Ahrens 		 * clause.
410*0af8f00bSMatthew Ahrens 		 */
411*0af8f00bSMatthew Ahrens 		if (prev_stmt != NULL)
412*0af8f00bSMatthew Ahrens 			prev_stmt->dn_list = NULL;
413*0af8f00bSMatthew Ahrens 
414*0af8f00bSMatthew Ahrens 		/*
415*0af8f00bSMatthew Ahrens 		 * Generate clause for statements preceding the "if"
416*0af8f00bSMatthew Ahrens 		 */
417*0af8f00bSMatthew Ahrens 		if (first_stmt_in_basic_block != NULL) {
418*0af8f00bSMatthew Ahrens 			dt_sugar_new_basic_block(dp, precondition,
419*0af8f00bSMatthew Ahrens 			    first_stmt_in_basic_block);
420*0af8f00bSMatthew Ahrens 		}
421*0af8f00bSMatthew Ahrens 
422*0af8f00bSMatthew Ahrens 		dt_sugar_do_if(dp, stmt, precondition);
423*0af8f00bSMatthew Ahrens 
424*0af8f00bSMatthew Ahrens 		first_stmt_in_basic_block = NULL;
425*0af8f00bSMatthew Ahrens 
426*0af8f00bSMatthew Ahrens 		prev_stmt = stmt;
427*0af8f00bSMatthew Ahrens 	}
428*0af8f00bSMatthew Ahrens 
429*0af8f00bSMatthew Ahrens 	/* generate clause for statements after last "if". */
430*0af8f00bSMatthew Ahrens 	if (first_stmt_in_basic_block != NULL) {
431*0af8f00bSMatthew Ahrens 		dt_sugar_new_basic_block(dp, precondition,
432*0af8f00bSMatthew Ahrens 		    first_stmt_in_basic_block);
433*0af8f00bSMatthew Ahrens 	}
434*0af8f00bSMatthew Ahrens }
435*0af8f00bSMatthew Ahrens 
436*0af8f00bSMatthew Ahrens /*
437*0af8f00bSMatthew Ahrens  * Generate a new clause which will set the error variable when an error occurs.
438*0af8f00bSMatthew Ahrens  * Only one of these clauses is created per program (e.g. script file).
439*0af8f00bSMatthew Ahrens  * The clause is:
440*0af8f00bSMatthew Ahrens  *
441*0af8f00bSMatthew Ahrens  * dtrace:::ERROR{ self->%error = 1; }
442*0af8f00bSMatthew Ahrens  */
443*0af8f00bSMatthew Ahrens static dt_node_t *
444*0af8f00bSMatthew Ahrens dt_sugar_makeerrorclause(void)
445*0af8f00bSMatthew Ahrens {
446*0af8f00bSMatthew Ahrens 	dt_node_t *acts, *pdesc;
447*0af8f00bSMatthew Ahrens 
448*0af8f00bSMatthew Ahrens 	pdesc = dt_node_pdesc_by_name(strdup("dtrace:::ERROR"));
449*0af8f00bSMatthew Ahrens 
450*0af8f00bSMatthew Ahrens 	acts = dt_node_statement(dt_node_op2(DT_TOK_ASGN,
451*0af8f00bSMatthew Ahrens 	    dt_sugar_new_error_var(), dt_node_int(1)));
452*0af8f00bSMatthew Ahrens 
453*0af8f00bSMatthew Ahrens 	return (dt_node_clause(pdesc, NULL, acts));
454*0af8f00bSMatthew Ahrens }
455*0af8f00bSMatthew Ahrens 
456*0af8f00bSMatthew Ahrens /*
457*0af8f00bSMatthew Ahrens  * Transform the super-clause into straight-D, returning the new list of
458*0af8f00bSMatthew Ahrens  * sub-clauses.
459*0af8f00bSMatthew Ahrens  */
460*0af8f00bSMatthew Ahrens dt_node_t *
461*0af8f00bSMatthew Ahrens dt_compile_sugar(dtrace_hdl_t *dtp, dt_node_t *clause)
462*0af8f00bSMatthew Ahrens {
463*0af8f00bSMatthew Ahrens 	dt_sugar_parse_t dp = { 0 };
464*0af8f00bSMatthew Ahrens 	int condid = 0;
465*0af8f00bSMatthew Ahrens 
466*0af8f00bSMatthew Ahrens 	dp.dtsp_dtp = dtp;
467*0af8f00bSMatthew Ahrens 	dp.dtsp_pdescs = clause->dn_pdescs;
468*0af8f00bSMatthew Ahrens 
469*0af8f00bSMatthew Ahrens 	/* make dt_node_int() generate an "int"-typed integer */
470*0af8f00bSMatthew Ahrens 	yyintdecimal = B_TRUE;
471*0af8f00bSMatthew Ahrens 	yyintsuffix[0] = '\0';
472*0af8f00bSMatthew Ahrens 	yyintprefix = 0;
473*0af8f00bSMatthew Ahrens 
474*0af8f00bSMatthew Ahrens 	dt_sugar_visit_all(&dp, clause);
475*0af8f00bSMatthew Ahrens 
476*0af8f00bSMatthew Ahrens 	if (dp.dtsp_num_ifs == 0 && dp.dtsp_num_conditions == 0) {
477*0af8f00bSMatthew Ahrens 		/*
478*0af8f00bSMatthew Ahrens 		 * There is nothing that modifies the number of clauses.  Use
479*0af8f00bSMatthew Ahrens 		 * the existing clause as-is, with its predicate intact.  This
480*0af8f00bSMatthew Ahrens 		 * ensures that in the absence of D sugar, the body of the
481*0af8f00bSMatthew Ahrens 		 * clause can create a variable that is referenced in the
482*0af8f00bSMatthew Ahrens 		 * predicate.
483*0af8f00bSMatthew Ahrens 		 */
484*0af8f00bSMatthew Ahrens 		dt_sugar_append_clause(&dp, dt_node_clause(clause->dn_pdescs,
485*0af8f00bSMatthew Ahrens 		    clause->dn_pred, clause->dn_acts));
486*0af8f00bSMatthew Ahrens 	} else {
487*0af8f00bSMatthew Ahrens 		if (clause->dn_pred != NULL) {
488*0af8f00bSMatthew Ahrens 			condid = dt_sugar_new_condition(&dp,
489*0af8f00bSMatthew Ahrens 			    clause->dn_pred, condid);
490*0af8f00bSMatthew Ahrens 		}
491*0af8f00bSMatthew Ahrens 
492*0af8f00bSMatthew Ahrens 		if (clause->dn_acts == NULL) {
493*0af8f00bSMatthew Ahrens 			/*
494*0af8f00bSMatthew Ahrens 			 * dt_sugar_visit_stmts() does not emit a clause with
495*0af8f00bSMatthew Ahrens 			 * an empty body (e.g. if there's an empty "if" body),
496*0af8f00bSMatthew Ahrens 			 * but we need the empty body here so that we
497*0af8f00bSMatthew Ahrens 			 * continue to get the default tracing action.
498*0af8f00bSMatthew Ahrens 			 */
499*0af8f00bSMatthew Ahrens 			dt_sugar_new_basic_block(&dp, condid, NULL);
500*0af8f00bSMatthew Ahrens 		} else {
501*0af8f00bSMatthew Ahrens 			dt_sugar_visit_stmts(&dp, clause->dn_acts, condid);
502*0af8f00bSMatthew Ahrens 		}
503*0af8f00bSMatthew Ahrens 	}
504*0af8f00bSMatthew Ahrens 
505*0af8f00bSMatthew Ahrens 	if (dp.dtsp_num_conditions != 0) {
506*0af8f00bSMatthew Ahrens 		dt_sugar_prepend_clause(&dp,
507*0af8f00bSMatthew Ahrens 		    dt_sugar_new_clearerror_clause(&dp));
508*0af8f00bSMatthew Ahrens 	}
509*0af8f00bSMatthew Ahrens 
510*0af8f00bSMatthew Ahrens 	if (dp.dtsp_clause_list != NULL &&
511*0af8f00bSMatthew Ahrens 	    dp.dtsp_clause_list->dn_list != NULL && !dtp->dt_has_sugar) {
512*0af8f00bSMatthew Ahrens 		dtp->dt_has_sugar = B_TRUE;
513*0af8f00bSMatthew Ahrens 		dt_sugar_prepend_clause(&dp, dt_sugar_makeerrorclause());
514*0af8f00bSMatthew Ahrens 	}
515*0af8f00bSMatthew Ahrens 	return (dp.dtsp_clause_list);
516*0af8f00bSMatthew Ahrens }
517