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