1 /* vm/jit/loop/tracing.c - trace functions
3 Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4 R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5 C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6 Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Christopher Kruegel
29 Contains the functions which create a trace. A trace is a
30 structure, that contains the source of the arguments of a given
31 instruction. For more details see function tracing(basicblock, int,
34 $Id: tracing.c 3617 2005-11-07 18:39:10Z twisti $
39 #include "mm/memory.h"
40 #include "vm/builtin.h"
41 #include "vm/resolve.h"
42 #include "vm/jit/loop/loop.h"
43 #include "vm/jit/loop/tracing.h"
46 /* Test function -> will be removed in final release
48 void printTraceResult(struct Trace *p)
57 printf("\tconst - %d", p->constant);
60 printf("\tarray - (%d)%d - %d", p->neg, p->var, p->constant);
63 printf("\tivar - (%d)%d - %d", p->neg, p->var, p->constant);
66 printf("\tavar - %d", p->var);
74 /* A function that creates a new trace structure and initializes its values
76 Trace* create_trace(int type, int var, int constant, int nr)
88 t->constant = constant;
94 /* When the function tracing(...) encounters an add instruction during its
95 backward scan over the instructions, it trys to identify the source of the
96 arguments of this add function. The following function performs this task.
98 Trace* add(Trace* a, Trace* b)
100 switch (a->type) { /* check the first argument of add. when it */
101 case TRACE_UNKNOWN: /* is unknown or array-address, return unknown */
103 return create_trace(TRACE_UNKNOWN, -1, 0, 0);
105 case TRACE_ICONST: /* when it is constant, check second argument */
107 case TRACE_IVAR: /* when second argument is a variable value */
108 case TRACE_ALENGTH: /* or array length, just add the constant */
112 a->constant += b->constant;
114 case TRACE_UNKNOWN: /* when unknown/array ref. return unknown */
116 return create_trace(TRACE_UNKNOWN, -1, 0, 0);
117 case TRACE_ICONST: /* when both are constant, just add them */
118 a->constant += b->constant;
123 case TRACE_IVAR: /* when it is a variable value or array length, */
124 case TRACE_ALENGTH: /* check second argument */
126 case TRACE_IVAR: /* when it is not a constant return unknown */
130 return create_trace(TRACE_UNKNOWN, -1, 0, 0);
131 case TRACE_ICONST: /* when it is a constant, just add it */
132 a->constant += b->constant;
142 /* When the function tracing(...) encounters a neg instruction during its
143 backward scan over the instructions, it trys to identify the source of the
144 argument of this neg function. The following function performs this task.
146 Trace* negate(Trace* a)
148 switch (a->type) { /* check argument type */
149 case TRACE_IVAR: /* when it is variable/array length value */
151 a->neg = -(a->neg); /* invert negate flag */
152 a->constant = -(a->constant); /* and negate constant */
155 case TRACE_ICONST: /* when it is a constant, negate it */
156 a->constant = -(a->constant);
160 a->type = TRACE_UNKNOWN; /* else return unknown */
168 /* When the function tracing(...) encounters a sub instruction during its backward
169 scan over the instructions, it trys to identify the source of the arguments of
170 this sub function. The following function performs this task, by applaying the
171 negate function on the second argument and then adds the values.
173 Trace* sub(Trace* a, Trace* b)
175 Trace *c = negate(b);
180 /* When the function tracing(...) encounters an array length instruction during
181 its backward scan over the instructions, it trys to identify the source of
182 the argument ofthis array length function. The following function performs
185 Trace* array_length(Trace* a)
187 if (a->type == TRACE_AVAR) /* if argument is an array ref., mark the type */
188 a->type = TRACE_ALENGTH; /* as array length of this array reference */
190 a->type = TRACE_UNKNOWN; /* else it's unknown */
196 /* tracing *********************************************************************
198 This function is used to identify the types of operands of an intermediate
199 code instruction. It is needed by functions, that analyze array accesses. If
200 something is stored into or loaded from an array, we have to find out,
201 which array really has been accessed. When a compare instruction is
202 encountered at a loop header, the type of its operands have to be detected
203 to construct dynamic bounds for some variables in the loop. This function
204 returns a struct Trace (see loop.h for more details about this structure).
205 block is the basic block to be examined, index holds the offset of the
206 examined instruction in this block. The arguments are retrieved by using
207 the stack structure, the compilation process sets up. During the backwards
208 scan of the code, it is possible, that other instructions temporary put or
209 get values from the stack and hide the value, we are interested in below
210 them. The value temp counts the number of values on the stack, the are
211 located beyond the target value.
213 *******************************************************************************/
215 Trace* tracing(basicblock *block, int index, int temp)
219 unresolved_method *um;
220 builtintable_entry *bte;
226 iptr = block->iinstr + index;
230 /* nop, nullcheckpop */
231 case ICMD_NOP: /* ... ==> ... */
232 return tracing(block, index - 1, temp);
235 case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */
236 return tracing(block, index-1, temp);
245 return tracing(block, index - 1, temp - 1);
247 return create_trace(TRACE_UNKNOWN, -1, 0, index);
251 if (temp > 0) /* if the target argument is not on top */
252 return tracing(block, index-1, temp-1); /* look further */
254 return create_trace(TRACE_ICONST, -1, iptr->val.i, index);
255 break; /* else, return the value, found at this instr. */
262 return tracing(block, index-1, temp-1);
264 return create_trace(TRACE_UNKNOWN, -1, 0, index);
269 return tracing(block, index-1, temp-1);
271 return create_trace(TRACE_IVAR, iptr->op1, 0, index);
276 return tracing(block, index-1, temp-1);
278 return create_trace(TRACE_AVAR, iptr->op1, 0, index);
286 return tracing(block, index-1, temp+1);
292 return tracing(block, index-1, temp+1);
296 return tracing(block, index-1, temp+2);
301 return tracing(block, index-1, temp-1);
303 return tracing(block, index-1, temp);
306 case ICMD_DUP_X1: /* ..., a, b ==> ..., b, a, b */
308 case 0: /* when looking for top or third element, */
309 case 2: /* just return top element */
310 return tracing(block, index-1, 0);
312 return tracing(block, index-1, 1);
314 return tracing(block, index-1, temp-1);
318 case ICMD_DUP2: /* ..., a, b ==> ..., a, b, a, b */
320 case 0: /* when looking for top or third element */
321 case 2: /* just return top element */
322 return tracing(block, index-1, 0);
323 case 1: /* when looking for second or fourth element*/
324 case 3: /* just return second element */
325 return tracing(block, index-1, 1);
327 return tracing(block, index-1, temp-2);
331 case ICMD_DUP2_X1: /* ..., a, b, c ==> ..., b, c, a, b, c */
335 return tracing(block, index-1, 0);
338 return tracing(block, index-1, 1);
340 return tracing(block, index-1, 2);
342 return tracing(block, index-1, temp-2);
346 case ICMD_DUP_X2: /* ..., a, b, c ==> ..., c, a, b, c */
350 return tracing(block, index-1, 0);
353 return tracing(block, index-1, 1);
355 return tracing(block, index-1, 2);
357 return tracing(block, index-1, temp-2);
361 case ICMD_DUP2_X2: /* .., a, b, c, d ==> ..., c, d, a, b, c, d */
365 return tracing(block, index-1, 0);
368 return tracing(block, index-1, 1);
370 return tracing(block, index-1, 2);
372 return tracing(block, index-1, 3);
374 return tracing(block, index-1, temp-2);
378 case ICMD_SWAP: /* ..., a, b ==> ..., b, a */
381 return tracing(block, index-1, 1);
383 return tracing(block, index-1, 0);
385 return tracing(block, index-1, temp);
389 /* Interger operations */
390 case ICMD_INEG: /* ..., value ==> ..., - value */
392 return tracing(block, index-1, temp);
393 else /* if an inter neg. operation is found, */
394 /* invokethe negate function */
395 return negate(tracing(block, index-1, temp));
398 case ICMD_LNEG: /* ..., value ==> ..., - value */
399 case ICMD_I2L: /* ..., value ==> ..., value */
400 case ICMD_L2I: /* ..., value ==> ..., value */
401 case ICMD_INT2BYTE: /* ..., value ==> ..., value */
402 case ICMD_INT2CHAR: /* ..., value ==> ..., value */
403 case ICMD_INT2SHORT: /* ..., value ==> ..., value */
405 return tracing(block, index-1, temp);
407 return create_trace(TRACE_UNKNOWN, -1, 0, index);
410 case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */
412 return tracing(block, index-1, temp+1);
413 else /* when add is encountered, invoke add func */
414 return add(tracing(block, index-1, 0), tracing(block, index-1, 1));
417 case ICMD_IADDCONST: /* ..., value ==> ..., value + constant */
419 return tracing(block, index-1, temp);
420 else /* when a constant is added, create a */
421 /* constant-trace and use add function */
422 return add(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, iptr->val.i, index));
425 case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */
427 return tracing(block, index-1, temp+1);
428 else /* use sub function for sub instructions */
429 return sub(tracing(block, index-1, 1), tracing(block, index-1, 0));
432 case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */
434 return tracing(block, index-1, temp);
436 return sub(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, iptr->val.i, index));
439 case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */
440 case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
441 case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
442 case ICMD_LMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
443 case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */
444 case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
445 case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
446 case ICMD_LSHL: /* ..., val1, val2 ==> ..., val1 << val2 */
447 case ICMD_LSHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
448 case ICMD_LUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
449 case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */
451 case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */
453 case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */
456 return tracing(block, index-1, temp+1);
458 return create_trace(TRACE_UNKNOWN, -1, 0, index);
461 case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */
462 case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */
463 case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */
464 case ICMD_LMULCONST: /* ..., value ==> ..., value * constant */
465 case ICMD_IDIVPOW2: /* ..., value ==> ..., value << constant */
466 case ICMD_LDIVPOW2: /* val.i = constant */
467 case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */
468 case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */
469 case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */
470 case ICMD_LSHLCONST: /* ..., value ==> ..., value << constant */
471 case ICMD_LSHRCONST: /* ..., value ==> ..., value >> constant */
472 case ICMD_LUSHRCONST: /* ..., value ==> ..., value >>> constant */
473 case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */
474 case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */
475 case ICMD_LANDCONST: /* ..., value ==> ..., value & constant */
476 case ICMD_LREMPOW2: /* ..., value ==> ..., value % constant */
477 case ICMD_IORCONST: /* ..., value ==> ..., value | constant */
478 case ICMD_LORCONST: /* ..., value ==> ..., value | constant */
479 case ICMD_IXORCONST: /* ..., value ==> ..., value ^ constant */
480 case ICMD_LXORCONST: /* ..., value ==> ..., value ^ constant */
481 case ICMD_LCMP: /* ..., val1, val2 ==> ..., val1 cmp val2 */
483 return tracing(block, index-1, temp);
485 return create_trace(TRACE_UNKNOWN, -1, 0, index);
488 case ICMD_IINC: /* ..., value ==> ..., value + constant */
489 return tracing(block, index-1, temp);
493 /* floating operations */
494 case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */
495 case ICMD_DADD: /* ..., val1, val2 ==> ..., val1 + val2 */
496 case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
497 case ICMD_DSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
498 case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
499 case ICMD_DMUL: /* ..., val1, val2 ==> ..., val1 *** val2 */
500 case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
501 case ICMD_DDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
502 case ICMD_FREM: /* ..., val1, val2 ==> ..., val1 % val2 */
503 case ICMD_DREM: /* ..., val1, val2 ==> ..., val1 % val2 */
504 case ICMD_FCMPL: /* .., val1, val2 ==> ..., val1 fcmpl val2 */
506 case ICMD_FCMPG: /* .., val1, val2 ==> ..., val1 fcmpg val2 */
509 return tracing(block, index-1, temp+1);
511 return create_trace(TRACE_UNKNOWN, -1, 0, index);
514 case ICMD_FNEG: /* ..., value ==> ..., - value */
515 case ICMD_DNEG: /* ..., value ==> ..., - value */
516 case ICMD_I2F: /* ..., value ==> ..., (float) value */
518 case ICMD_I2D: /* ..., value ==> ..., (double) value */
520 case ICMD_F2I: /* ..., value ==> ..., (int) value */
522 case ICMD_F2L: /* ..., value ==> ..., (long) value */
524 case ICMD_F2D: /* ..., value ==> ..., (double) value */
525 case ICMD_D2F: /* ..., value ==> ..., (double) value */
527 return tracing(block, index-1, temp);
529 return create_trace(TRACE_UNKNOWN, -1, 0, index);
532 /* memory operations */
533 case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., length */
535 return tracing(block, index-1, temp);
537 return array_length(tracing(block, index-1, 0));
540 case ICMD_AALOAD: /* ..., arrayref, index ==> ..., value */
541 case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */
542 case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */
543 case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */
544 case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */
545 case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */
546 case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */
547 case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */
549 return tracing(block, index-1, temp+1);
551 return create_trace(TRACE_UNKNOWN, -1, 0, index);
554 case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */
555 case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */
556 case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */
557 case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */
558 case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */
559 case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */
560 case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */
561 case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */
562 return tracing(block, index-1, temp+3);
565 case ICMD_PUTSTATIC: /* ..., value ==> ... */
566 case ICMD_PUTFIELD: /* ..., value ==> ... */
567 return tracing(block, index - 1, temp + 1);
570 case ICMD_GETSTATIC: /* ... ==> ..., value */
571 case ICMD_GETFIELD: /* ... ==> ..., value */
573 return tracing(block, index-1, temp - 1);
575 return create_trace(TRACE_UNKNOWN, -1, 0, index);
579 /* branch: should not be encountered, but function calls possible */
581 case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */
582 case ICMD_INVOKESPECIAL: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
583 case ICMD_INVOKEVIRTUAL:
584 case ICMD_INVOKEINTERFACE:
585 m = iptr->val.a; /* get method pointer and */
591 md = um->methodref->parseddesc.md;
594 args = md->paramcount; /* number of arguments */
596 if (md->returntype.type != TYPE_VOID)
597 retval = 1; /* if function returns a value, it is on */
598 else /* top of stack */
601 if (temp > 0) /* temp is increased by number of */
602 /* arguments a possible result value */
603 return tracing(block, index - 1, temp + (args - retval));
605 return create_trace(TRACE_UNKNOWN, -1, 0, index);
611 case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */
612 case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */
614 return tracing(block, index-1, temp);
616 return create_trace(TRACE_UNKNOWN, -1, 0, index);
619 case ICMD_MULTIANEWARRAY: /* ..., cnt1, [cnt2, ...] ==> ..., arrayref */
620 /* op1 = dimension */
622 if (temp > 0) /* temp increased by number of dimensions */
623 /* minus one for array ref */
624 return tracing(block, index - 1, temp + (iptr->op1 - 1));
626 return create_trace(TRACE_UNKNOWN, -1, 0, index);
629 case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */
632 args = md->paramcount;
633 if (md->returntype.type != TYPE_VOID)
638 if (temp > 0) /* temp is increased by number of */
639 /* arguments less a possible result value */
640 return tracing(block, index - 1, temp + (args - retval));
642 return create_trace(TRACE_UNKNOWN, -1, 0, index);
649 return create_trace(TRACE_UNKNOWN, -1, 0, index);
654 return create_trace(TRACE_UNKNOWN, -1, 0, index);
659 * These are local overrides for various environment variables in Emacs.
660 * Please do not remove this and leave it at the end of the file, where
661 * Emacs will automagically detect them.
662 * ---------------------------------------------------------------------
665 * indent-tabs-mode: t