1 /* vm/jit/loop/tracing.c - trace functions
3 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
5 M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
6 P. Tomsich, J. Wenninger
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 1621 2004-11-30 13:06:55Z twisti $
39 /* #include <stdio.h> */
41 #include "mm/memory.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)
222 ip = block->iinstr+index;
224 /* printf("TRACING with %d %d %d\n", index, temp, ip->opc);
228 /* nop, nullcheckpop */
229 case ICMD_NOP: /* ... ==> ... */
230 return tracing(block, index-1, temp);
233 case ICMD_NULLCHECKPOP: /* ..., objectref ==> ... */
234 return tracing(block, index-1, temp+1);
243 return tracing(block, index-1, temp-1);
245 return create_trace(TRACE_UNKNOWN, -1, 0, index);
249 if (temp > 0) /* if the target argument is not on top */
250 return tracing(block, index-1, temp-1); /* look further */
252 return create_trace(TRACE_ICONST, -1, ip->val.i, index);
253 break; /* else, return the value, found at this instr. */
260 return tracing(block, index-1, temp-1);
262 return create_trace(TRACE_UNKNOWN, -1, 0, index);
267 return tracing(block, index-1, temp-1);
269 return create_trace(TRACE_IVAR, ip->op1, 0, index);
274 return tracing(block, index-1, temp-1);
276 return create_trace(TRACE_AVAR, ip->op1, 0, index);
284 return tracing(block, index-1, temp+1);
290 return tracing(block, index-1, temp+1);
294 return tracing(block, index-1, temp+2);
299 return tracing(block, index-1, temp-1);
301 return tracing(block, index-1, temp);
304 case ICMD_DUP_X1: /* ..., a, b ==> ..., b, a, b */
306 case 0: /* when looking for top or third element, */
307 case 2: /* just return top element */
308 return tracing(block, index-1, 0);
310 return tracing(block, index-1, 1);
312 return tracing(block, index-1, temp-1);
316 case ICMD_DUP2: /* ..., a, b ==> ..., a, b, a, b */
318 case 0: /* when looking for top or third element */
319 case 2: /* just return top element */
320 return tracing(block, index-1, 0);
321 case 1: /* when looking for second or fourth element*/
322 case 3: /* just return second element */
323 return tracing(block, index-1, 1);
325 return tracing(block, index-1, temp-2);
329 case ICMD_DUP2_X1: /* ..., a, b, c ==> ..., b, c, a, b, c */
333 return tracing(block, index-1, 0);
336 return tracing(block, index-1, 1);
338 return tracing(block, index-1, 2);
340 return tracing(block, index-1, temp-2);
344 case ICMD_DUP_X2: /* ..., a, b, c ==> ..., c, a, b, c */
348 return tracing(block, index-1, 0);
351 return tracing(block, index-1, 1);
353 return tracing(block, index-1, 2);
355 return tracing(block, index-1, temp-2);
359 case ICMD_DUP2_X2: /* .., a, b, c, d ==> ..., c, d, a, b, c, d */
363 return tracing(block, index-1, 0);
366 return tracing(block, index-1, 1);
368 return tracing(block, index-1, 2);
370 return tracing(block, index-1, 3);
372 return tracing(block, index-1, temp-2);
376 case ICMD_SWAP: /* ..., a, b ==> ..., b, a */
379 return tracing(block, index-1, 1);
381 return tracing(block, index-1, 0);
383 return tracing(block, index-1, temp);
387 /* Interger operations */
388 case ICMD_INEG: /* ..., value ==> ..., - value */
390 return tracing(block, index-1, temp);
391 else /* if an inter neg. operation is found, */
392 /* invokethe negate function */
393 return negate(tracing(block, index-1, temp));
396 case ICMD_LNEG: /* ..., value ==> ..., - value */
397 case ICMD_I2L: /* ..., value ==> ..., value */
398 case ICMD_L2I: /* ..., value ==> ..., value */
399 case ICMD_INT2BYTE: /* ..., value ==> ..., value */
400 case ICMD_INT2CHAR: /* ..., value ==> ..., value */
401 case ICMD_INT2SHORT: /* ..., value ==> ..., value */
403 return tracing(block, index-1, temp);
405 return create_trace(TRACE_UNKNOWN, -1, 0, index);
408 case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */
410 return tracing(block, index-1, temp+1);
411 else /* when add is encountered, invoke add func */
412 return add(tracing(block, index-1, 0), tracing(block, index-1, 1));
415 case ICMD_IADDCONST: /* ..., value ==> ..., value + constant */
417 return tracing(block, index-1, temp);
418 else /* when a constant is added, create a */
419 /* constant-trace and use add function */
420 return add(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, ip->val.i, index));
423 case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */
425 return tracing(block, index-1, temp+1);
426 else /* use sub function for sub instructions */
427 return sub(tracing(block, index-1, 1), tracing(block, index-1, 0));
430 case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */
432 return tracing(block, index-1, temp);
434 return sub(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, ip->val.i, index));
437 case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */
438 case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
439 case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
440 case ICMD_LMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
441 case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */
442 case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
443 case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
444 case ICMD_LSHL: /* ..., val1, val2 ==> ..., val1 << val2 */
445 case ICMD_LSHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
446 case ICMD_LUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
447 case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */
449 case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */
451 case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */
454 return tracing(block, index-1, temp+1);
456 return create_trace(TRACE_UNKNOWN, -1, 0, index);
459 case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */
460 case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */
461 case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */
462 case ICMD_LMULCONST: /* ..., value ==> ..., value * constant */
463 case ICMD_IDIVPOW2: /* ..., value ==> ..., value << constant */
464 case ICMD_LDIVPOW2: /* val.i = constant */
465 case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */
466 case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */
467 case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */
468 case ICMD_LSHLCONST: /* ..., value ==> ..., value << constant */
469 case ICMD_LSHRCONST: /* ..., value ==> ..., value >> constant */
470 case ICMD_LUSHRCONST: /* ..., value ==> ..., value >>> constant */
471 case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */
472 case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */
473 case ICMD_LANDCONST: /* ..., value ==> ..., value & constant */
474 case ICMD_LREMPOW2: /* ..., value ==> ..., value % constant */
475 case ICMD_IORCONST: /* ..., value ==> ..., value | constant */
476 case ICMD_LORCONST: /* ..., value ==> ..., value | constant */
477 case ICMD_IXORCONST: /* ..., value ==> ..., value ^ constant */
478 case ICMD_LXORCONST: /* ..., value ==> ..., value ^ constant */
479 case ICMD_LCMP: /* ..., val1, val2 ==> ..., val1 cmp val2 */
481 return tracing(block, index-1, temp);
483 return create_trace(TRACE_UNKNOWN, -1, 0, index);
486 case ICMD_IINC: /* ..., value ==> ..., value + constant */
487 return tracing(block, index-1, temp);
491 /* floating operations */
492 case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */
493 case ICMD_DADD: /* ..., val1, val2 ==> ..., val1 + val2 */
494 case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
495 case ICMD_DSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
496 case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
497 case ICMD_DMUL: /* ..., val1, val2 ==> ..., val1 *** val2 */
498 case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
499 case ICMD_DDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
500 case ICMD_FREM: /* ..., val1, val2 ==> ..., val1 % val2 */
501 case ICMD_DREM: /* ..., val1, val2 ==> ..., val1 % val2 */
502 case ICMD_FCMPL: /* .., val1, val2 ==> ..., val1 fcmpl val2 */
504 case ICMD_FCMPG: /* .., val1, val2 ==> ..., val1 fcmpg val2 */
507 return tracing(block, index-1, temp+1);
509 return create_trace(TRACE_UNKNOWN, -1, 0, index);
512 case ICMD_FNEG: /* ..., value ==> ..., - value */
513 case ICMD_DNEG: /* ..., value ==> ..., - value */
514 case ICMD_I2F: /* ..., value ==> ..., (float) value */
516 case ICMD_I2D: /* ..., value ==> ..., (double) value */
518 case ICMD_F2I: /* ..., value ==> ..., (int) value */
520 case ICMD_F2L: /* ..., value ==> ..., (long) value */
522 case ICMD_F2D: /* ..., value ==> ..., (double) value */
523 case ICMD_D2F: /* ..., value ==> ..., (double) value */
525 return tracing(block, index-1, temp);
527 return create_trace(TRACE_UNKNOWN, -1, 0, index);
530 /* memory operations */
531 case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., length */
533 return tracing(block, index-1, temp);
535 return array_length(tracing(block, index-1, 0));
538 case ICMD_AALOAD: /* ..., arrayref, index ==> ..., value */
539 case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */
540 case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */
541 case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */
542 case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */
543 case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */
544 case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */
545 case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */
547 return tracing(block, index-1, temp+1);
549 return create_trace(TRACE_UNKNOWN, -1, 0, index);
552 case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */
553 case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */
554 case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */
555 case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */
556 case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */
557 case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */
558 case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */
559 case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */
560 return tracing(block, index-1, temp+3);
563 case ICMD_PUTSTATIC: /* ..., value ==> ... */
564 case ICMD_PUTFIELD: /* ..., value ==> ... */
565 return tracing(block, index-1, temp+1);
568 case ICMD_GETSTATIC: /* ... ==> ..., value */
569 case ICMD_GETFIELD: /* ... ==> ..., value */
571 return tracing(block, index-1, temp-1);
573 return create_trace(TRACE_UNKNOWN, -1, 0, index);
577 /* branch: should not be encountered, but function calls possible */
578 case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */
579 m = ip->val.a; /* get method pointer and */
580 args = ip->op1; /* number of arguments */
581 if (m->returntype != TYPE_VOID)
582 retval = 1; /* if function returns a value, it is on */
583 else /* top of stack */
586 if (temp > 0) /* temp is increased by number of arguments */
587 /* less a possible result value */
588 return tracing(block, index-1, temp+(args-retval));
590 return create_trace(TRACE_UNKNOWN, -1, 0, index);
593 case ICMD_INVOKESPECIAL: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
594 case ICMD_INVOKEVIRTUAL: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
595 case ICMD_INVOKEINTERFACE: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
598 if (m->returntype != TYPE_VOID)
603 if (temp > 0) /* same as above but add 1 for object ref */
604 return tracing(block, index-1, temp+(args-retval+1));
606 return create_trace(TRACE_UNKNOWN, -1, 0, index);
610 case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */
611 case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */
613 return tracing(block, index-1, temp);
615 return create_trace(TRACE_UNKNOWN, -1, 0, index);
618 case ICMD_MULTIANEWARRAY: /* ..., cnt1, [cnt2, ...] ==> ..., arrayref */
619 /* op1 = dimension */
621 if (temp > 0) /* temp increased by number of dimensions */
622 /* minus one for array ref */
623 return tracing(block, index-1, temp+(ip->op1 - 1));
625 return create_trace(TRACE_UNKNOWN, -1, 0, index);
628 case ICMD_BUILTIN3: /* ..., arg1, arg2, arg3 ==> ... */
629 if (ip->op1 != TYPE_VOID)
634 if (temp > 0) /* increase temp by 3 minus possible return */
636 return tracing(block, index-1, temp+(3-retval));
638 return create_trace(TRACE_UNKNOWN, -1, 0, index);
641 case ICMD_BUILTIN2: /* ..., arg1, arg2 ==> ... */
642 if (ip->op1 != TYPE_VOID)
647 return tracing(block, index-1, temp+(2-retval));
649 return create_trace(TRACE_UNKNOWN, -1, 0, index);
652 case ICMD_BUILTIN1: /* ..., arg1 ==> ... */
653 if (ip->op1 != TYPE_VOID)
658 return tracing(block, index-1, temp+(1-retval));
660 return create_trace(TRACE_UNKNOWN, -1, 0, index);
665 return create_trace(TRACE_UNKNOWN, -1, 0, index);
669 return create_trace(TRACE_UNKNOWN, -1, 0, index);
674 * These are local overrides for various environment variables in Emacs.
675 * Please do not remove this and leave it at the end of the file, where
676 * Emacs will automagically detect them.
677 * ---------------------------------------------------------------------
680 * indent-tabs-mode: t