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 *
dt_sugar_new_error_var(void)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
dt_sugar_append_clause(dt_sugar_parse_t * dp,dt_node_t * clause)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
dt_sugar_prepend_clause(dt_sugar_parse_t * dp,dt_node_t * clause)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 *
dt_sugar_new_condition_var(int condid)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 *
dt_sugar_new_condition_impl(dt_sugar_parse_t * dp,dt_node_t * pred,int condid,int newcond)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
dt_sugar_new_condition(dt_sugar_parse_t * dp,dt_node_t * pred,int condid)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
dt_sugar_visit_all(dt_sugar_parse_t * dp,dt_node_t * dnp)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 *
dt_sugar_new_clearerror_clause(dt_sugar_parse_t * dp)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
dt_sugar_do_if(dt_sugar_parse_t * dp,dt_node_t * if_stmt,int precondition)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
dt_sugar_new_basic_block(dt_sugar_parse_t * dp,int condid,dt_node_t * stmts)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
dt_sugar_visit_stmts(dt_sugar_parse_t * dp,dt_node_t * stmts,int precondition)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 *
dt_sugar_makeerrorclause(void)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 *
dt_compile_sugar(dtrace_hdl_t * dtp,dt_node_t * clause)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