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