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 576 2003-11-09 17:31:38Z twisti $
42 #include "toolbox/memory.h"
45 /* Test function -> will be removed in final release
47 void printTraceResult(struct Trace *p)
56 printf("\tconst - %d", p->constant);
59 printf("\tarray - (%d)%d - %d", p->neg, p->var, p->constant);
62 printf("\tivar - (%d)%d - %d", p->neg, p->var, p->constant);
65 printf("\tavar - %d", p->var);
73 /* A function that creates a new trace structure and initializes its values
75 struct Trace* create_trace(int type, int var, int constant, int nr)
78 /* if ((t = (struct Trace *) malloc(sizeof(struct Trace))) == NULL) */
80 t = DNEW(struct Trace);
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 struct Trace* add(struct Trace* a, struct 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 struct Trace* negate(struct 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 struct Trace* sub(struct Trace* a, struct Trace* b)
175 struct 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 struct Trace* array_length(struct 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 /* This function is used to identify the types of operands of an intermediate
197 code instruction.It is needed by functions, that analyze array accesses. If
198 something is stored into or loaded from an array, we have to find out, which
199 array really has been accessed. When a compare instruction is encountered at
200 a loop header, the type of its operands have to be detected to construct
201 dynamic bounds for some variables in the loop. This function returns a struct
202 Trace (see loop.h for more details about this structure). block is the basic
203 block to be examined, index holds the offset of the examined instruction in
204 this block. The arguments are retrieved by using the stack structure, the
205 compilation process sets up. During the backwards scan of the code, it is
206 possible, that other instructions temporaray put or get values from the stack
207 and hide the value, we are interested in below them. The value temp counts
208 the number of values on the stack, the are located beyond the target value.
210 struct Trace* tracing(basicblock *block, int index, int temp)
217 ip = block->iinstr+index;
219 /* printf("TRACING with %d %d %d\n", index, temp, ip->opc);
223 /* nop, nullcheckpop */
224 case ICMD_NOP: /* ... ==> ... */
225 return tracing(block, index-1, temp);
228 case ICMD_NULLCHECKPOP: /* ..., objectref ==> ... */
229 return tracing(block, index-1, temp+1);
238 return tracing(block, index-1, temp-1);
240 return create_trace(TRACE_UNKNOWN, -1, 0, index);
244 if (temp > 0) /* if the target argument is not on top */
245 return tracing(block, index-1, temp-1); /* look further */
247 return create_trace(TRACE_ICONST, -1, ip->val.i, index);
248 break; /* else, return the value, found at this instr. */
255 return tracing(block, index-1, temp-1);
257 return create_trace(TRACE_UNKNOWN, -1, 0, index);
262 return tracing(block, index-1, temp-1);
264 return create_trace(TRACE_IVAR, ip->op1, 0, index);
269 return tracing(block, index-1, temp-1);
271 return create_trace(TRACE_AVAR, ip->op1, 0, index);
279 return tracing(block, index-1, temp+1);
285 return tracing(block, index-1, temp+1);
289 return tracing(block, index-1, temp+2);
294 return tracing(block, index-1, temp-1);
296 return tracing(block, index-1, temp);
299 case ICMD_DUP_X1: /* ..., a, b ==> ..., b, a, b */
301 case 0: /* when looking for top or third element, */
302 case 2: /* just return top element */
303 return tracing(block, index-1, 0);
305 return tracing(block, index-1, 1);
307 return tracing(block, index-1, temp-1);
311 case ICMD_DUP2: /* ..., a, b ==> ..., a, b, a, b */
313 case 0: /* when looking for top or third element */
314 case 2: /* just return top element */
315 return tracing(block, index-1, 0);
316 case 1: /* when looking for second or fourth element*/
317 case 3: /* just return second element */
318 return tracing(block, index-1, 1);
320 return tracing(block, index-1, temp-2);
324 case ICMD_DUP2_X1: /* ..., a, b, c ==> ..., b, c, a, b, c */
328 return tracing(block, index-1, 0);
331 return tracing(block, index-1, 1);
333 return tracing(block, index-1, 2);
335 return tracing(block, index-1, temp-2);
339 case ICMD_DUP_X2: /* ..., a, b, c ==> ..., c, a, b, c */
343 return tracing(block, index-1, 0);
346 return tracing(block, index-1, 1);
348 return tracing(block, index-1, 2);
350 return tracing(block, index-1, temp-2);
354 case ICMD_DUP2_X2: /* .., a, b, c, d ==> ..., c, d, a, b, c, d */
358 return tracing(block, index-1, 0);
361 return tracing(block, index-1, 1);
363 return tracing(block, index-1, 2);
365 return tracing(block, index-1, 3);
367 return tracing(block, index-1, temp-2);
371 case ICMD_SWAP: /* ..., a, b ==> ..., b, a */
374 return tracing(block, index-1, 1);
376 return tracing(block, index-1, 0);
378 return tracing(block, index-1, temp);
382 /* Interger operations */
383 case ICMD_INEG: /* ..., value ==> ..., - value */
385 return tracing(block, index-1, temp);
386 else /* if an inter neg. operation is found, */
387 /* invokethe negate function */
388 return negate(tracing(block, index-1, temp));
391 case ICMD_LNEG: /* ..., value ==> ..., - value */
392 case ICMD_I2L: /* ..., value ==> ..., value */
393 case ICMD_L2I: /* ..., value ==> ..., value */
394 case ICMD_INT2BYTE: /* ..., value ==> ..., value */
395 case ICMD_INT2CHAR: /* ..., value ==> ..., value */
396 case ICMD_INT2SHORT: /* ..., value ==> ..., value */
398 return tracing(block, index-1, temp);
400 return create_trace(TRACE_UNKNOWN, -1, 0, index);
403 case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */
405 return tracing(block, index-1, temp+1);
406 else /* when add is encountered, invoke add func */
407 return add(tracing(block, index-1, 0), tracing(block, index-1, 1));
410 case ICMD_IADDCONST: /* ..., value ==> ..., value + constant */
412 return tracing(block, index-1, temp);
413 else /* when a constant is added, create a */
414 /* constant-trace and use add function */
415 return add(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, ip->val.i, index));
418 case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */
420 return tracing(block, index-1, temp+1);
421 else /* use sub function for sub instructions */
422 return sub(tracing(block, index-1, 1), tracing(block, index-1, 0));
425 case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */
427 return tracing(block, index-1, temp);
429 return sub(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, ip->val.i, index));
432 case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */
433 case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
434 case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
435 case ICMD_LMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
436 case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */
437 case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
438 case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
439 case ICMD_LSHL: /* ..., val1, val2 ==> ..., val1 << val2 */
440 case ICMD_LSHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
441 case ICMD_LUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
442 case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */
444 case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */
446 case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */
449 return tracing(block, index-1, temp+1);
451 return create_trace(TRACE_UNKNOWN, -1, 0, index);
454 case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */
455 case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */
456 case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */
457 case ICMD_LMULCONST: /* ..., value ==> ..., value * constant */
458 case ICMD_IDIVPOW2: /* ..., value ==> ..., value << constant */
459 case ICMD_LDIVPOW2: /* val.i = constant */
460 case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */
461 case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */
462 case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */
463 case ICMD_LSHLCONST: /* ..., value ==> ..., value << constant */
464 case ICMD_LSHRCONST: /* ..., value ==> ..., value >> constant */
465 case ICMD_LUSHRCONST: /* ..., value ==> ..., value >>> constant */
466 case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */
467 case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */
468 case ICMD_IREM0X10001: /* ..., value ==> ..., value % 0x100001 */
469 case ICMD_LANDCONST: /* ..., value ==> ..., value & constant */
470 case ICMD_LREMPOW2: /* ..., value ==> ..., value % constant */
471 case ICMD_LREM0X10001: /* ..., value ==> ..., value % 0x10001 */
472 case ICMD_IORCONST: /* ..., value ==> ..., value | constant */
473 case ICMD_LORCONST: /* ..., value ==> ..., value | constant */
474 case ICMD_IXORCONST: /* ..., value ==> ..., value ^ constant */
475 case ICMD_LXORCONST: /* ..., value ==> ..., value ^ constant */
476 case ICMD_LCMP: /* ..., val1, val2 ==> ..., val1 cmp val2 */
478 return tracing(block, index-1, temp);
480 return create_trace(TRACE_UNKNOWN, -1, 0, index);
483 case ICMD_IINC: /* ..., value ==> ..., value + constant */
484 return tracing(block, index-1, temp);
488 /* floating operations */
489 case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */
490 case ICMD_DADD: /* ..., val1, val2 ==> ..., val1 + val2 */
491 case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
492 case ICMD_DSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
493 case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
494 case ICMD_DMUL: /* ..., val1, val2 ==> ..., val1 *** val2 */
495 case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
496 case ICMD_DDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
497 case ICMD_FREM: /* ..., val1, val2 ==> ..., val1 % val2 */
498 case ICMD_DREM: /* ..., val1, val2 ==> ..., val1 % val2 */
499 case ICMD_FCMPL: /* .., val1, val2 ==> ..., val1 fcmpl val2 */
501 case ICMD_FCMPG: /* .., val1, val2 ==> ..., val1 fcmpg val2 */
504 return tracing(block, index-1, temp+1);
506 return create_trace(TRACE_UNKNOWN, -1, 0, index);
509 case ICMD_FNEG: /* ..., value ==> ..., - value */
510 case ICMD_DNEG: /* ..., value ==> ..., - value */
511 case ICMD_I2F: /* ..., value ==> ..., (float) value */
513 case ICMD_I2D: /* ..., value ==> ..., (double) value */
515 case ICMD_F2I: /* ..., value ==> ..., (int) value */
517 case ICMD_F2L: /* ..., value ==> ..., (long) value */
519 case ICMD_F2D: /* ..., value ==> ..., (double) value */
520 case ICMD_D2F: /* ..., value ==> ..., (double) value */
522 return tracing(block, index-1, temp);
524 return create_trace(TRACE_UNKNOWN, -1, 0, index);
527 /* memory operations */
528 case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., length */
530 return tracing(block, index-1, temp);
532 return array_length(tracing(block, index-1, 0));
535 case ICMD_AALOAD: /* ..., arrayref, index ==> ..., value */
536 case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */
537 case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */
538 case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */
539 case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */
540 case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */
541 case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */
542 case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */
544 return tracing(block, index-1, temp+1);
546 return create_trace(TRACE_UNKNOWN, -1, 0, index);
549 case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */
550 case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */
551 case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */
552 case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */
553 case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */
554 case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */
555 case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */
556 case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */
557 return tracing(block, index-1, temp+3);
560 case ICMD_PUTSTATIC: /* ..., value ==> ... */
561 case ICMD_PUTFIELD: /* ..., value ==> ... */
562 return tracing(block, index-1, temp+1);
565 case ICMD_GETSTATIC: /* ... ==> ..., value */
566 case ICMD_GETFIELD: /* ... ==> ..., value */
568 return tracing(block, index-1, temp-1);
570 return create_trace(TRACE_UNKNOWN, -1, 0, index);
574 /* branch: should not be encountered, but function calls possible */
575 case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */
576 m = ip->val.a; /* get method pointer and */
577 args = ip->op1; /* number of arguments */
578 if (m->returntype != TYPE_VOID)
579 retval = 1; /* if function returns a value, it is on */
580 else /* top of stack */
583 if (temp > 0) /* temp is increased by number of arguments */
584 /* less a possible result value */
585 return tracing(block, index-1, temp+(args-retval));
587 return create_trace(TRACE_UNKNOWN, -1, 0, index);
590 case ICMD_INVOKESPECIAL: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
591 case ICMD_INVOKEVIRTUAL: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
592 case ICMD_INVOKEINTERFACE: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
595 if (m->returntype != TYPE_VOID)
600 if (temp > 0) /* same as above but add 1 for object ref */
601 return tracing(block, index-1, temp+(args-retval+1));
603 return create_trace(TRACE_UNKNOWN, -1, 0, index);
607 case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */
608 case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */
610 return tracing(block, index-1, temp);
612 return create_trace(TRACE_UNKNOWN, -1, 0, index);
615 case ICMD_MULTIANEWARRAY: /* ..., cnt1, [cnt2, ...] ==> ..., arrayref */
616 /* op1 = dimension */
618 if (temp > 0) /* temp increased by number of dimensions */
619 /* minus one for array ref */
620 return tracing(block, index-1, temp+(ip->op1 - 1));
622 return create_trace(TRACE_UNKNOWN, -1, 0, index);
625 case ICMD_BUILTIN3: /* ..., arg1, arg2, arg3 ==> ... */
626 if (ip->op1 != TYPE_VOID)
631 if (temp > 0) /* increase temp by 3 minus possible return */
633 return tracing(block, index-1, temp+(3-retval));
635 return create_trace(TRACE_UNKNOWN, -1, 0, index);
638 case ICMD_BUILTIN2: /* ..., arg1, arg2 ==> ... */
639 if (ip->op1 != TYPE_VOID)
644 return tracing(block, index-1, temp+(2-retval));
646 return create_trace(TRACE_UNKNOWN, -1, 0, index);
649 case ICMD_BUILTIN1: /* ..., arg1 ==> ... */
650 if (ip->op1 != TYPE_VOID)
655 return tracing(block, index-1, temp+(1-retval));
657 return create_trace(TRACE_UNKNOWN, -1, 0, index);
662 return create_trace(TRACE_UNKNOWN, -1, 0, index);
666 return create_trace(TRACE_UNKNOWN, -1, 0, index);
671 * These are local overrides for various environment variables in Emacs.
672 * Please do not remove this and leave it at the end of the file, where
673 * Emacs will automagically detect them.
674 * ---------------------------------------------------------------------
677 * indent-tabs-mode: t