Performance: split check deliver fast/slow paths
[lttng-ust.git] / liblttng-ust / lttng-filter-specialize.c
CommitLineData
97b58163
MD
1/*
2 * lttng-filter-specialize.c
3 *
4 * LTTng UST filter code specializer.
5 *
6 * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; only
11 * version 2.1 of the License.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include "lttng-filter.h"
24
25int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode)
26{
27 void *pc, *next_pc, *start_pc;
28 int ret = -EINVAL;
0305960f
MD
29 struct vstack _stack;
30 struct vstack *stack = &_stack;
97b58163 31
0305960f 32 vstack_init(stack);
97b58163
MD
33
34 start_pc = &bytecode->data[0];
35 for (pc = next_pc = start_pc; pc - start_pc < bytecode->len;
36 pc = next_pc) {
37 switch (*(filter_opcode_t *) pc) {
38 case FILTER_OP_UNKNOWN:
39 default:
40 ERR("unknown bytecode op %u\n",
41 (unsigned int) *(filter_opcode_t *) pc);
42 ret = -EINVAL;
43 goto end;
44
45 case FILTER_OP_RETURN:
46 ret = 0;
47 goto end;
48
49 /* binary */
50 case FILTER_OP_MUL:
51 case FILTER_OP_DIV:
52 case FILTER_OP_MOD:
53 case FILTER_OP_PLUS:
54 case FILTER_OP_MINUS:
55 case FILTER_OP_RSHIFT:
56 case FILTER_OP_LSHIFT:
57 case FILTER_OP_BIN_AND:
58 case FILTER_OP_BIN_OR:
59 case FILTER_OP_BIN_XOR:
60 ERR("unsupported bytecode op %u\n",
61 (unsigned int) *(filter_opcode_t *) pc);
62 ret = -EINVAL;
63 goto end;
64
65 case FILTER_OP_EQ:
66 {
67 struct binary_op *insn = (struct binary_op *) pc;
68
0305960f 69 switch(vstack_ax(stack)->type) {
97b58163
MD
70 default:
71 ERR("unknown register type\n");
72 ret = -EINVAL;
73 goto end;
74
75 case REG_STRING:
53569322
MD
76 if (vstack_bx(stack)->type == REG_UNKNOWN)
77 break;
97b58163
MD
78 insn->op = FILTER_OP_EQ_STRING;
79 break;
80 case REG_S64:
53569322
MD
81 if (vstack_bx(stack)->type == REG_UNKNOWN)
82 break;
0305960f 83 if (vstack_bx(stack)->type == REG_S64)
97b58163
MD
84 insn->op = FILTER_OP_EQ_S64;
85 else
dbea82ec 86 insn->op = FILTER_OP_EQ_DOUBLE_S64;
97b58163
MD
87 break;
88 case REG_DOUBLE:
53569322
MD
89 if (vstack_bx(stack)->type == REG_UNKNOWN)
90 break;
dbea82ec
MD
91 if (vstack_bx(stack)->type == REG_S64)
92 insn->op = FILTER_OP_EQ_S64_DOUBLE;
93 else
94 insn->op = FILTER_OP_EQ_DOUBLE;
97b58163 95 break;
53569322
MD
96 case REG_UNKNOWN:
97 break; /* Dynamic typing. */
97b58163 98 }
0305960f
MD
99 /* Pop 2, push 1 */
100 if (vstack_pop(stack)) {
101 ret = -EINVAL;
102 goto end;
103 }
104 vstack_ax(stack)->type = REG_S64;
97b58163
MD
105 next_pc += sizeof(struct binary_op);
106 break;
107 }
108
109 case FILTER_OP_NE:
110 {
111 struct binary_op *insn = (struct binary_op *) pc;
112
0305960f 113 switch(vstack_ax(stack)->type) {
97b58163
MD
114 default:
115 ERR("unknown register type\n");
116 ret = -EINVAL;
117 goto end;
118
119 case REG_STRING:
53569322
MD
120 if (vstack_bx(stack)->type == REG_UNKNOWN)
121 break;
97b58163
MD
122 insn->op = FILTER_OP_NE_STRING;
123 break;
124 case REG_S64:
53569322
MD
125 if (vstack_bx(stack)->type == REG_UNKNOWN)
126 break;
0305960f 127 if (vstack_bx(stack)->type == REG_S64)
97b58163
MD
128 insn->op = FILTER_OP_NE_S64;
129 else
dbea82ec 130 insn->op = FILTER_OP_NE_DOUBLE_S64;
97b58163
MD
131 break;
132 case REG_DOUBLE:
53569322
MD
133 if (vstack_bx(stack)->type == REG_UNKNOWN)
134 break;
dbea82ec
MD
135 if (vstack_bx(stack)->type == REG_S64)
136 insn->op = FILTER_OP_NE_S64_DOUBLE;
137 else
138 insn->op = FILTER_OP_NE_DOUBLE;
97b58163 139 break;
53569322
MD
140 case REG_UNKNOWN:
141 break; /* Dynamic typing. */
97b58163 142 }
0305960f
MD
143 /* Pop 2, push 1 */
144 if (vstack_pop(stack)) {
145 ret = -EINVAL;
146 goto end;
147 }
148 vstack_ax(stack)->type = REG_S64;
97b58163
MD
149 next_pc += sizeof(struct binary_op);
150 break;
151 }
152
153 case FILTER_OP_GT:
154 {
155 struct binary_op *insn = (struct binary_op *) pc;
156
0305960f 157 switch(vstack_ax(stack)->type) {
97b58163
MD
158 default:
159 ERR("unknown register type\n");
160 ret = -EINVAL;
161 goto end;
162
163 case REG_STRING:
53569322
MD
164 if (vstack_bx(stack)->type == REG_UNKNOWN)
165 break;
97b58163
MD
166 insn->op = FILTER_OP_GT_STRING;
167 break;
168 case REG_S64:
53569322
MD
169 if (vstack_bx(stack)->type == REG_UNKNOWN)
170 break;
0305960f 171 if (vstack_bx(stack)->type == REG_S64)
97b58163
MD
172 insn->op = FILTER_OP_GT_S64;
173 else
dbea82ec 174 insn->op = FILTER_OP_GT_DOUBLE_S64;
97b58163
MD
175 break;
176 case REG_DOUBLE:
53569322
MD
177 if (vstack_bx(stack)->type == REG_UNKNOWN)
178 break;
dbea82ec
MD
179 if (vstack_bx(stack)->type == REG_S64)
180 insn->op = FILTER_OP_GT_S64_DOUBLE;
181 else
182 insn->op = FILTER_OP_GT_DOUBLE;
97b58163 183 break;
53569322
MD
184 case REG_UNKNOWN:
185 break; /* Dynamic typing. */
97b58163 186 }
0305960f
MD
187 /* Pop 2, push 1 */
188 if (vstack_pop(stack)) {
189 ret = -EINVAL;
190 goto end;
191 }
192 vstack_ax(stack)->type = REG_S64;
97b58163
MD
193 next_pc += sizeof(struct binary_op);
194 break;
195 }
196
197 case FILTER_OP_LT:
198 {
199 struct binary_op *insn = (struct binary_op *) pc;
200
0305960f 201 switch(vstack_ax(stack)->type) {
97b58163
MD
202 default:
203 ERR("unknown register type\n");
204 ret = -EINVAL;
205 goto end;
206
207 case REG_STRING:
53569322
MD
208 if (vstack_bx(stack)->type == REG_UNKNOWN)
209 break;
97b58163
MD
210 insn->op = FILTER_OP_LT_STRING;
211 break;
212 case REG_S64:
53569322
MD
213 if (vstack_bx(stack)->type == REG_UNKNOWN)
214 break;
0305960f 215 if (vstack_bx(stack)->type == REG_S64)
97b58163
MD
216 insn->op = FILTER_OP_LT_S64;
217 else
dbea82ec 218 insn->op = FILTER_OP_LT_DOUBLE_S64;
97b58163
MD
219 break;
220 case REG_DOUBLE:
53569322
MD
221 if (vstack_bx(stack)->type == REG_UNKNOWN)
222 break;
dbea82ec
MD
223 if (vstack_bx(stack)->type == REG_S64)
224 insn->op = FILTER_OP_LT_S64_DOUBLE;
225 else
226 insn->op = FILTER_OP_LT_DOUBLE;
97b58163 227 break;
53569322
MD
228 case REG_UNKNOWN:
229 break; /* Dynamic typing. */
97b58163 230 }
0305960f
MD
231 /* Pop 2, push 1 */
232 if (vstack_pop(stack)) {
233 ret = -EINVAL;
234 goto end;
235 }
236 vstack_ax(stack)->type = REG_S64;
97b58163
MD
237 next_pc += sizeof(struct binary_op);
238 break;
239 }
240
241 case FILTER_OP_GE:
242 {
243 struct binary_op *insn = (struct binary_op *) pc;
244
0305960f 245 switch(vstack_ax(stack)->type) {
97b58163
MD
246 default:
247 ERR("unknown register type\n");
248 ret = -EINVAL;
249 goto end;
250
251 case REG_STRING:
53569322
MD
252 if (vstack_bx(stack)->type == REG_UNKNOWN)
253 break;
97b58163
MD
254 insn->op = FILTER_OP_GE_STRING;
255 break;
256 case REG_S64:
53569322
MD
257 if (vstack_bx(stack)->type == REG_UNKNOWN)
258 break;
0305960f 259 if (vstack_bx(stack)->type == REG_S64)
97b58163
MD
260 insn->op = FILTER_OP_GE_S64;
261 else
dbea82ec 262 insn->op = FILTER_OP_GE_DOUBLE_S64;
97b58163
MD
263 break;
264 case REG_DOUBLE:
53569322
MD
265 if (vstack_bx(stack)->type == REG_UNKNOWN)
266 break;
dbea82ec
MD
267 if (vstack_bx(stack)->type == REG_S64)
268 insn->op = FILTER_OP_GE_S64_DOUBLE;
269 else
270 insn->op = FILTER_OP_GE_DOUBLE;
97b58163 271 break;
53569322
MD
272 case REG_UNKNOWN:
273 break; /* Dynamic typing. */
97b58163 274 }
0305960f
MD
275 /* Pop 2, push 1 */
276 if (vstack_pop(stack)) {
277 ret = -EINVAL;
278 goto end;
279 }
280 vstack_ax(stack)->type = REG_S64;
97b58163
MD
281 next_pc += sizeof(struct binary_op);
282 break;
283 }
284 case FILTER_OP_LE:
285 {
286 struct binary_op *insn = (struct binary_op *) pc;
287
0305960f 288 switch(vstack_ax(stack)->type) {
97b58163
MD
289 default:
290 ERR("unknown register type\n");
291 ret = -EINVAL;
292 goto end;
293
294 case REG_STRING:
53569322
MD
295 if (vstack_bx(stack)->type == REG_UNKNOWN)
296 break;
97b58163
MD
297 insn->op = FILTER_OP_LE_STRING;
298 break;
299 case REG_S64:
53569322
MD
300 if (vstack_bx(stack)->type == REG_UNKNOWN)
301 break;
0305960f 302 if (vstack_bx(stack)->type == REG_S64)
97b58163
MD
303 insn->op = FILTER_OP_LE_S64;
304 else
dbea82ec 305 insn->op = FILTER_OP_LE_DOUBLE_S64;
97b58163
MD
306 break;
307 case REG_DOUBLE:
53569322
MD
308 if (vstack_bx(stack)->type == REG_UNKNOWN)
309 break;
dbea82ec
MD
310 if (vstack_bx(stack)->type == REG_S64)
311 insn->op = FILTER_OP_LE_S64_DOUBLE;
312 else
313 insn->op = FILTER_OP_LE_DOUBLE;
97b58163 314 break;
53569322
MD
315 case REG_UNKNOWN:
316 break; /* Dynamic typing. */
97b58163 317 }
0305960f 318 vstack_ax(stack)->type = REG_S64;
97b58163
MD
319 next_pc += sizeof(struct binary_op);
320 break;
321 }
322
323 case FILTER_OP_EQ_STRING:
324 case FILTER_OP_NE_STRING:
325 case FILTER_OP_GT_STRING:
326 case FILTER_OP_LT_STRING:
327 case FILTER_OP_GE_STRING:
328 case FILTER_OP_LE_STRING:
329 case FILTER_OP_EQ_S64:
330 case FILTER_OP_NE_S64:
331 case FILTER_OP_GT_S64:
332 case FILTER_OP_LT_S64:
333 case FILTER_OP_GE_S64:
334 case FILTER_OP_LE_S64:
335 case FILTER_OP_EQ_DOUBLE:
336 case FILTER_OP_NE_DOUBLE:
337 case FILTER_OP_GT_DOUBLE:
338 case FILTER_OP_LT_DOUBLE:
339 case FILTER_OP_GE_DOUBLE:
340 case FILTER_OP_LE_DOUBLE:
dbea82ec
MD
341 case FILTER_OP_EQ_DOUBLE_S64:
342 case FILTER_OP_NE_DOUBLE_S64:
343 case FILTER_OP_GT_DOUBLE_S64:
344 case FILTER_OP_LT_DOUBLE_S64:
345 case FILTER_OP_GE_DOUBLE_S64:
346 case FILTER_OP_LE_DOUBLE_S64:
347 case FILTER_OP_EQ_S64_DOUBLE:
348 case FILTER_OP_NE_S64_DOUBLE:
349 case FILTER_OP_GT_S64_DOUBLE:
350 case FILTER_OP_LT_S64_DOUBLE:
351 case FILTER_OP_GE_S64_DOUBLE:
352 case FILTER_OP_LE_S64_DOUBLE:
97b58163 353 {
0305960f
MD
354 /* Pop 2, push 1 */
355 if (vstack_pop(stack)) {
356 ret = -EINVAL;
357 goto end;
358 }
359 vstack_ax(stack)->type = REG_S64;
97b58163
MD
360 next_pc += sizeof(struct binary_op);
361 break;
362 }
363
364 /* unary */
365 case FILTER_OP_UNARY_PLUS:
366 {
367 struct unary_op *insn = (struct unary_op *) pc;
368
0305960f 369 switch(vstack_ax(stack)->type) {
97b58163
MD
370 default:
371 ERR("unknown register type\n");
372 ret = -EINVAL;
373 goto end;
374
375 case REG_S64:
376 insn->op = FILTER_OP_UNARY_PLUS_S64;
377 break;
378 case REG_DOUBLE:
379 insn->op = FILTER_OP_UNARY_PLUS_DOUBLE;
380 break;
53569322
MD
381 case REG_UNKNOWN: /* Dynamic typing. */
382 break;
97b58163 383 }
0305960f 384 /* Pop 1, push 1 */
97b58163
MD
385 next_pc += sizeof(struct unary_op);
386 break;
387 }
388
389 case FILTER_OP_UNARY_MINUS:
390 {
391 struct unary_op *insn = (struct unary_op *) pc;
392
0305960f 393 switch(vstack_ax(stack)->type) {
97b58163
MD
394 default:
395 ERR("unknown register type\n");
396 ret = -EINVAL;
397 goto end;
398
399 case REG_S64:
400 insn->op = FILTER_OP_UNARY_MINUS_S64;
401 break;
402 case REG_DOUBLE:
403 insn->op = FILTER_OP_UNARY_MINUS_DOUBLE;
404 break;
53569322
MD
405 case REG_UNKNOWN: /* Dynamic typing. */
406 break;
97b58163 407 }
0305960f 408 /* Pop 1, push 1 */
97b58163
MD
409 next_pc += sizeof(struct unary_op);
410 break;
411 }
412
413 case FILTER_OP_UNARY_NOT:
414 {
415 struct unary_op *insn = (struct unary_op *) pc;
416
0305960f 417 switch(vstack_ax(stack)->type) {
97b58163
MD
418 default:
419 ERR("unknown register type\n");
420 ret = -EINVAL;
421 goto end;
422
423 case REG_S64:
424 insn->op = FILTER_OP_UNARY_NOT_S64;
425 break;
426 case REG_DOUBLE:
427 insn->op = FILTER_OP_UNARY_NOT_DOUBLE;
428 break;
53569322
MD
429 case REG_UNKNOWN: /* Dynamic typing. */
430 break;
97b58163 431 }
0305960f 432 /* Pop 1, push 1 */
97b58163
MD
433 next_pc += sizeof(struct unary_op);
434 break;
435 }
436
437 case FILTER_OP_UNARY_PLUS_S64:
438 case FILTER_OP_UNARY_MINUS_S64:
439 case FILTER_OP_UNARY_NOT_S64:
440 case FILTER_OP_UNARY_PLUS_DOUBLE:
441 case FILTER_OP_UNARY_MINUS_DOUBLE:
442 case FILTER_OP_UNARY_NOT_DOUBLE:
443 {
0305960f 444 /* Pop 1, push 1 */
97b58163
MD
445 next_pc += sizeof(struct unary_op);
446 break;
447 }
448
449 /* logical */
450 case FILTER_OP_AND:
451 case FILTER_OP_OR:
452 {
b9f4cd79
MD
453 /* Continue to next instruction */
454 /* Pop 1 when jump not taken */
455 if (vstack_pop(stack)) {
456 ret = -EINVAL;
457 goto end;
458 }
97b58163
MD
459 next_pc += sizeof(struct logical_op);
460 break;
461 }
462
77aa5901 463 /* load field ref */
97b58163
MD
464 case FILTER_OP_LOAD_FIELD_REF:
465 {
466 ERR("Unknown field ref type\n");
467 ret = -EINVAL;
468 goto end;
469 }
77aa5901
MD
470 /* get context ref */
471 case FILTER_OP_GET_CONTEXT_REF:
472 {
53569322
MD
473 if (vstack_push(stack)) {
474 ret = -EINVAL;
475 goto end;
476 }
477 vstack_ax(stack)->type = REG_UNKNOWN;
478 next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
479 break;
77aa5901 480 }
97b58163
MD
481 case FILTER_OP_LOAD_FIELD_REF_STRING:
482 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE:
77aa5901 483 case FILTER_OP_GET_CONTEXT_REF_STRING:
97b58163 484 {
0305960f
MD
485 if (vstack_push(stack)) {
486 ret = -EINVAL;
487 goto end;
488 }
489 vstack_ax(stack)->type = REG_STRING;
97b58163
MD
490 next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
491 break;
492 }
493 case FILTER_OP_LOAD_FIELD_REF_S64:
77aa5901 494 case FILTER_OP_GET_CONTEXT_REF_S64:
97b58163 495 {
0305960f
MD
496 if (vstack_push(stack)) {
497 ret = -EINVAL;
498 goto end;
499 }
500 vstack_ax(stack)->type = REG_S64;
97b58163
MD
501 next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
502 break;
503 }
504 case FILTER_OP_LOAD_FIELD_REF_DOUBLE:
77aa5901 505 case FILTER_OP_GET_CONTEXT_REF_DOUBLE:
97b58163 506 {
0305960f
MD
507 if (vstack_push(stack)) {
508 ret = -EINVAL;
509 goto end;
510 }
511 vstack_ax(stack)->type = REG_DOUBLE;
97b58163
MD
512 next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
513 break;
514 }
515
77aa5901 516 /* load from immediate operand */
97b58163
MD
517 case FILTER_OP_LOAD_STRING:
518 {
519 struct load_op *insn = (struct load_op *) pc;
520
0305960f
MD
521 if (vstack_push(stack)) {
522 ret = -EINVAL;
523 goto end;
524 }
525 vstack_ax(stack)->type = REG_STRING;
97b58163
MD
526 next_pc += sizeof(struct load_op) + strlen(insn->data) + 1;
527 break;
528 }
529
530 case FILTER_OP_LOAD_S64:
531 {
0305960f
MD
532 if (vstack_push(stack)) {
533 ret = -EINVAL;
534 goto end;
535 }
536 vstack_ax(stack)->type = REG_S64;
97b58163
MD
537 next_pc += sizeof(struct load_op)
538 + sizeof(struct literal_numeric);
539 break;
540 }
541
542 case FILTER_OP_LOAD_DOUBLE:
543 {
0305960f
MD
544 if (vstack_push(stack)) {
545 ret = -EINVAL;
546 goto end;
547 }
548 vstack_ax(stack)->type = REG_DOUBLE;
97b58163
MD
549 next_pc += sizeof(struct load_op)
550 + sizeof(struct literal_double);
551 break;
552 }
553
554 /* cast */
555 case FILTER_OP_CAST_TO_S64:
556 {
557 struct cast_op *insn = (struct cast_op *) pc;
558
0305960f 559 switch (vstack_ax(stack)->type) {
97b58163
MD
560 default:
561 ERR("unknown register type\n");
562 ret = -EINVAL;
563 goto end;
564
565 case REG_STRING:
566 ERR("Cast op can only be applied to numeric or floating point registers\n");
567 ret = -EINVAL;
568 goto end;
569 case REG_S64:
570 insn->op = FILTER_OP_CAST_NOP;
571 break;
572 case REG_DOUBLE:
573 insn->op = FILTER_OP_CAST_DOUBLE_TO_S64;
574 break;
53569322
MD
575 case REG_UNKNOWN:
576 break;
97b58163 577 }
0305960f
MD
578 /* Pop 1, push 1 */
579 vstack_ax(stack)->type = REG_S64;
97b58163
MD
580 next_pc += sizeof(struct cast_op);
581 break;
582 }
583 case FILTER_OP_CAST_DOUBLE_TO_S64:
584 {
0305960f
MD
585 /* Pop 1, push 1 */
586 vstack_ax(stack)->type = REG_S64;
97b58163
MD
587 next_pc += sizeof(struct cast_op);
588 break;
589 }
590 case FILTER_OP_CAST_NOP:
591 {
592 next_pc += sizeof(struct cast_op);
593 break;
594 }
595
97b58163
MD
596 }
597 }
598end:
599 return ret;
600}
This page took 0.05129 seconds and 4 git commands to generate.