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