1 /* 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 557 2003-11-02 22:51:59Z twisti $
44 /* Test function -> will be removed in final release
46 void printTraceResult(struct Trace *p)
55 printf("\tconst - %d", p->constant);
58 printf("\tarray - (%d)%d - %d", p->neg, p->var, p->constant);
61 printf("\tivar - (%d)%d - %d", p->neg, p->var, p->constant);
64 printf("\tavar - %d", p->var);
72 /* A function that creates a new trace structure and initializes its values
74 struct Trace* create_trace(int type, int var, int constant, int nr)
77 if ((t = (struct Trace *) malloc(sizeof(struct Trace))) == NULL)
86 t->constant = constant;
92 /* When the function tracing(...) encounters an add instruction during its
93 backward scan over the instructions, it trys to identify the source of the
94 arguments of this add function. The following function performs this task.
96 struct Trace* add(struct Trace* a, struct Trace* b)
98 switch (a->type) { /* check the first argument of add. when it */
99 case TRACE_UNKNOWN: /* is unknown or array-address, return unknown */
101 return create_trace(TRACE_UNKNOWN, -1, 0, 0);
103 case TRACE_ICONST: /* when it is constant, check second argument */
105 case TRACE_IVAR: /* when second argument is a variable value */
106 case TRACE_ALENGTH: /* or array length, just add the constant */
110 a->constant += b->constant;
112 case TRACE_UNKNOWN: /* when unknown/array ref. return unknown */
114 return create_trace(TRACE_UNKNOWN, -1, 0, 0);
115 case TRACE_ICONST: /* when both are constant, just add them */
116 a->constant += b->constant;
121 case TRACE_IVAR: /* when it is a variable value or array length, */
122 case TRACE_ALENGTH: /* check second argument */
124 case TRACE_IVAR: /* when it is not a constant return unknown */
128 return create_trace(TRACE_UNKNOWN, -1, 0, 0);
129 case TRACE_ICONST: /* when it is a constant, just add it */
130 a->constant += b->constant;
140 /* When the function tracing(...) encounters a neg instruction during its
141 backward scan over the instructions, it trys to identify the source of the
142 argument of this neg function. The following function performs this task.
144 struct Trace* negate(struct Trace* a)
146 switch (a->type) { /* check argument type */
147 case TRACE_IVAR: /* when it is variable/array length value */
149 a->neg = -(a->neg); /* invert negate flag */
150 a->constant = -(a->constant); /* and negate constant */
153 case TRACE_ICONST: /* when it is a constant, negate it */
154 a->constant = -(a->constant);
158 a->type = TRACE_UNKNOWN; /* else return unknown */
166 /* When the function tracing(...) encounters a sub instruction during its backward
167 scan over the instructions, it trys to identify the source of the arguments of
168 this sub function. The following function performs this task, by applaying the
169 negate function on the second argument and then adds the values.
171 struct Trace* sub(struct Trace* a, struct Trace* b)
173 struct Trace *c = negate(b);
178 /* When the function tracing(...) encounters an array length instruction during
179 its backward scan over the instructions, it trys to identify the source of
180 the argument ofthis array length function. The following function performs
183 struct Trace* array_length(struct Trace* a)
185 if (a->type == TRACE_AVAR) /* if argument is an array ref., mark the type */
186 a->type = TRACE_ALENGTH; /* as array length of this array reference */
188 a->type = TRACE_UNKNOWN; /* else it's unknown */
194 /* This function is used to identify the types of operands of an intermediate
195 code instruction.It is needed by functions, that analyze array accesses. If
196 something is stored into or loaded from an array, we have to find out, which
197 array really has been accessed. When a compare instruction is encountered at
198 a loop header, the type of its operands have to be detected to construct
199 dynamic bounds for some variables in the loop. This function returns a struct
200 Trace (see loop.h for more details about this structure). block is the basic
201 block to be examined, index holds the offset of the examined instruction in
202 this block. The arguments are retrieved by using the stack structure, the
203 compilation process sets up. During the backwards scan of the code, it is
204 possible, that other instructions temporaray put or get values from the stack
205 and hide the value, we are interested in below them. The value temp counts
206 the number of values on the stack, the are located beyond the target value.
208 struct Trace* tracing(basicblock *block, int index, int temp)
215 ip = block->iinstr+index;
217 /* printf("TRACING with %d %d %d\n", index, temp, ip->opc);
221 /* nop, nullcheckpop */
222 case ICMD_NOP: /* ... ==> ... */
223 return tracing(block, index-1, temp);
226 case ICMD_NULLCHECKPOP: /* ..., objectref ==> ... */
227 return tracing(block, index-1, temp+1);
236 return tracing(block, index-1, temp-1);
238 return create_trace(TRACE_UNKNOWN, -1, 0, index);
242 if (temp > 0) /* if the target argument is not on top */
243 return tracing(block, index-1, temp-1); /* look further */
245 return create_trace(TRACE_ICONST, -1, ip->val.i, index);
246 break; /* else, return the value, found at this instr. */
253 return tracing(block, index-1, temp-1);
255 return create_trace(TRACE_UNKNOWN, -1, 0, index);
260 return tracing(block, index-1, temp-1);
262 return create_trace(TRACE_IVAR, ip->op1, 0, index);
267 return tracing(block, index-1, temp-1);
269 return create_trace(TRACE_AVAR, ip->op1, 0, index);
277 return tracing(block, index-1, temp+1);
283 return tracing(block, index-1, temp+1);
287 return tracing(block, index-1, temp+2);
292 return tracing(block, index-1, temp-1);
294 return tracing(block, index-1, temp);
297 case ICMD_DUP_X1: /* ..., a, b ==> ..., b, a, b */
299 case 0: /* when looking for top or third element, */
300 case 2: /* just return top element */
301 return tracing(block, index-1, 0);
303 return tracing(block, index-1, 1);
305 return tracing(block, index-1, temp-1);
309 case ICMD_DUP2: /* ..., a, b ==> ..., a, b, a, b */
311 case 0: /* when looking for top or third element */
312 case 2: /* just return top element */
313 return tracing(block, index-1, 0);
314 case 1: /* when looking for second or fourth element*/
315 case 3: /* just return second element */
316 return tracing(block, index-1, 1);
318 return tracing(block, index-1, temp-2);
322 case ICMD_DUP2_X1: /* ..., a, b, c ==> ..., b, c, a, b, c */
326 return tracing(block, index-1, 0);
329 return tracing(block, index-1, 1);
331 return tracing(block, index-1, 2);
333 return tracing(block, index-1, temp-2);
337 case ICMD_DUP_X2: /* ..., a, b, c ==> ..., c, a, b, c */
341 return tracing(block, index-1, 0);
344 return tracing(block, index-1, 1);
346 return tracing(block, index-1, 2);
348 return tracing(block, index-1, temp-2);
352 case ICMD_DUP2_X2: /* .., a, b, c, d ==> ..., c, d, a, b, c, d */
356 return tracing(block, index-1, 0);
359 return tracing(block, index-1, 1);
361 return tracing(block, index-1, 2);
363 return tracing(block, index-1, 3);
365 return tracing(block, index-1, temp-2);
369 case ICMD_SWAP: /* ..., a, b ==> ..., b, a */
372 return tracing(block, index-1, 1);
374 return tracing(block, index-1, 0);
376 return tracing(block, index-1, temp);
380 /* Interger operations */
381 case ICMD_INEG: /* ..., value ==> ..., - value */
383 return tracing(block, index-1, temp);
384 else /* if an inter neg. operation is found, */
385 /* invokethe negate function */
386 return negate(tracing(block, index-1, temp));
389 case ICMD_LNEG: /* ..., value ==> ..., - value */
390 case ICMD_I2L: /* ..., value ==> ..., value */
391 case ICMD_L2I: /* ..., value ==> ..., value */
392 case ICMD_INT2BYTE: /* ..., value ==> ..., value */
393 case ICMD_INT2CHAR: /* ..., value ==> ..., value */
394 case ICMD_INT2SHORT: /* ..., value ==> ..., value */
396 return tracing(block, index-1, temp);
398 return create_trace(TRACE_UNKNOWN, -1, 0, index);
401 case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */
403 return tracing(block, index-1, temp+1);
404 else /* when add is encountered, invoke add func */
405 return add(tracing(block, index-1, 0), tracing(block, index-1, 1));
408 case ICMD_IADDCONST: /* ..., value ==> ..., value + constant */
410 return tracing(block, index-1, temp);
411 else /* when a constant is added, create a */
412 /* constant-trace and use add function */
413 return add(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, ip->val.i, index));
416 case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */
418 return tracing(block, index-1, temp+1);
419 else /* use sub function for sub instructions */
420 return sub(tracing(block, index-1, 1), tracing(block, index-1, 0));
423 case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */
425 return tracing(block, index-1, temp);
427 return sub(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, ip->val.i, index));
430 case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */
431 case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
432 case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
433 case ICMD_LMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
434 case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */
435 case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
436 case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
437 case ICMD_LSHL: /* ..., val1, val2 ==> ..., val1 << val2 */
438 case ICMD_LSHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
439 case ICMD_LUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
440 case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */
442 case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */
444 case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */
447 return tracing(block, index-1, temp+1);
449 return create_trace(TRACE_UNKNOWN, -1, 0, index);
452 case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */
453 case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */
454 case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */
455 case ICMD_LMULCONST: /* ..., value ==> ..., value * constant */
456 case ICMD_IDIVPOW2: /* ..., value ==> ..., value << constant */
457 case ICMD_LDIVPOW2: /* val.i = constant */
458 case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */
459 case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */
460 case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */
461 case ICMD_LSHLCONST: /* ..., value ==> ..., value << constant */
462 case ICMD_LSHRCONST: /* ..., value ==> ..., value >> constant */
463 case ICMD_LUSHRCONST: /* ..., value ==> ..., value >>> constant */
464 case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */
465 case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */
466 case ICMD_IREM0X10001: /* ..., value ==> ..., value % 0x100001 */
467 case ICMD_LANDCONST: /* ..., value ==> ..., value & constant */
468 case ICMD_LREMPOW2: /* ..., value ==> ..., value % constant */
469 case ICMD_LREM0X10001: /* ..., value ==> ..., value % 0x10001 */
470 case ICMD_IORCONST: /* ..., value ==> ..., value | constant */
471 case ICMD_LORCONST: /* ..., value ==> ..., value | constant */
472 case ICMD_IXORCONST: /* ..., value ==> ..., value ^ constant */
473 case ICMD_LXORCONST: /* ..., value ==> ..., value ^ constant */
474 case ICMD_LCMP: /* ..., val1, val2 ==> ..., val1 cmp val2 */
476 return tracing(block, index-1, temp);
478 return create_trace(TRACE_UNKNOWN, -1, 0, index);
481 case ICMD_IINC: /* ..., value ==> ..., value + constant */
482 return tracing(block, index-1, temp);
486 /* floating operations */
487 case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */
488 case ICMD_DADD: /* ..., val1, val2 ==> ..., val1 + val2 */
489 case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
490 case ICMD_DSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
491 case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
492 case ICMD_DMUL: /* ..., val1, val2 ==> ..., val1 *** val2 */
493 case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
494 case ICMD_DDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
495 case ICMD_FREM: /* ..., val1, val2 ==> ..., val1 % val2 */
496 case ICMD_DREM: /* ..., val1, val2 ==> ..., val1 % val2 */
497 case ICMD_FCMPL: /* .., val1, val2 ==> ..., val1 fcmpl val2 */
499 case ICMD_FCMPG: /* .., val1, val2 ==> ..., val1 fcmpg val2 */
502 return tracing(block, index-1, temp+1);
504 return create_trace(TRACE_UNKNOWN, -1, 0, index);
507 case ICMD_FNEG: /* ..., value ==> ..., - value */
508 case ICMD_DNEG: /* ..., value ==> ..., - value */
509 case ICMD_I2F: /* ..., value ==> ..., (float) value */
511 case ICMD_I2D: /* ..., value ==> ..., (double) value */
513 case ICMD_F2I: /* ..., value ==> ..., (int) value */
515 case ICMD_F2L: /* ..., value ==> ..., (long) value */
517 case ICMD_F2D: /* ..., value ==> ..., (double) value */
518 case ICMD_D2F: /* ..., value ==> ..., (double) value */
520 return tracing(block, index-1, temp);
522 return create_trace(TRACE_UNKNOWN, -1, 0, index);
525 /* memory operations */
526 case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., length */
528 return tracing(block, index-1, temp);
530 return array_length(tracing(block, index-1, 0));
533 case ICMD_AALOAD: /* ..., arrayref, index ==> ..., value */
534 case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */
535 case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */
536 case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */
537 case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */
538 case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */
539 case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */
540 case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */
542 return tracing(block, index-1, temp+1);
544 return create_trace(TRACE_UNKNOWN, -1, 0, index);
547 case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */
548 case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */
549 case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */
550 case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */
551 case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */
552 case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */
553 case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */
554 case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */
555 return tracing(block, index-1, temp+3);
558 case ICMD_PUTSTATIC: /* ..., value ==> ... */
559 case ICMD_PUTFIELD: /* ..., value ==> ... */
560 return tracing(block, index-1, temp+1);
563 case ICMD_GETSTATIC: /* ... ==> ..., value */
564 case ICMD_GETFIELD: /* ... ==> ..., value */
566 return tracing(block, index-1, temp-1);
568 return create_trace(TRACE_UNKNOWN, -1, 0, index);
572 /* branch: should not be encountered, but function calls possible */
573 case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */
574 m = ip->val.a; /* get method pointer and */
575 args = ip->op1; /* number of arguments */
576 if (m->returntype != TYPE_VOID)
577 retval = 1; /* if function returns a value, it is on */
578 else /* top of stack */
581 if (temp > 0) /* temp is increased by number of arguments */
582 /* less a possible result value */
583 return tracing(block, index-1, temp+(args-retval));
585 return create_trace(TRACE_UNKNOWN, -1, 0, index);
588 case ICMD_INVOKESPECIAL: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
589 case ICMD_INVOKEVIRTUAL: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
590 case ICMD_INVOKEINTERFACE: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
593 if (m->returntype != TYPE_VOID)
598 if (temp > 0) /* same as above but add 1 for object ref */
599 return tracing(block, index-1, temp+(args-retval+1));
601 return create_trace(TRACE_UNKNOWN, -1, 0, index);
605 case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */
606 case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */
608 return tracing(block, index-1, temp);
610 return create_trace(TRACE_UNKNOWN, -1, 0, index);
613 case ICMD_MULTIANEWARRAY: /* ..., cnt1, [cnt2, ...] ==> ..., arrayref */
614 /* op1 = dimension */
616 if (temp > 0) /* temp increased by number of dimensions */
617 /* minus one for array ref */
618 return tracing(block, index-1, temp+(ip->op1 - 1));
620 return create_trace(TRACE_UNKNOWN, -1, 0, index);
623 case ICMD_BUILTIN3: /* ..., arg1, arg2, arg3 ==> ... */
624 if (ip->op1 != TYPE_VOID)
629 if (temp > 0) /* increase temp by 3 minus possible return */
631 return tracing(block, index-1, temp+(3-retval));
633 return create_trace(TRACE_UNKNOWN, -1, 0, index);
636 case ICMD_BUILTIN2: /* ..., arg1, arg2 ==> ... */
637 if (ip->op1 != TYPE_VOID)
642 return tracing(block, index-1, temp+(2-retval));
644 return create_trace(TRACE_UNKNOWN, -1, 0, index);
647 case ICMD_BUILTIN1: /* ..., arg1 ==> ... */
648 if (ip->op1 != TYPE_VOID)
653 return tracing(block, index-1, temp+(1-retval));
655 return create_trace(TRACE_UNKNOWN, -1, 0, index);
660 return create_trace(TRACE_UNKNOWN, -1, 0, index);
664 return create_trace(TRACE_UNKNOWN, -1, 0, index);
669 * These are local overrides for various environment variables in Emacs.
670 * Please do not remove this and leave it at the end of the file, where
671 * Emacs will automagically detect them.
672 * ---------------------------------------------------------------------
675 * indent-tabs-mode: t