1 /* tracing.c *******************************************************************
3 Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst
5 See file COPYRIGHT for information on usage and disclaimer of warranties.
7 Contains the functions which create a trace. A trace is a structure, that
8 contains the source of the arguments of a given instruction. For more
9 details see function tracing(basicblock, int, int) below.
11 Authors: Christopher Kruegel EMAIL: cacao@complang.tuwien.ac.at
13 Last Change: 1998/17/02
15 *******************************************************************************/
17 /* Test function -> will be removed in final release
19 void printTraceResult(struct Trace *p)
28 printf("\tconst - %d", p->constant);
31 printf("\tarray - (%d)%d - %d", p->neg, p->var, p->constant);
34 printf("\tivar - (%d)%d - %d", p->neg, p->var, p->constant);
37 printf("\tavar - %d", p->var);
45 /* A function that creates a new trace structure and initializes its values
47 struct Trace* create_trace(int type, int var, int constant, int nr)
50 if ((t = (struct Trace *) malloc(sizeof(struct Trace))) == NULL)
59 t->constant = constant;
64 /* When the function tracing(...) encounters an add instruction during its
65 backward scan over the instructions, it trys to identify the source of the
66 arguments of this add function. The following function performs this task.
68 struct Trace* add(struct Trace* a, struct Trace* b)
70 switch (a->type) { /* check the first argument of add. when it */
71 case TRACE_UNKNOWN: /* is unknown or array-address, return unknown */
73 return create_trace(TRACE_UNKNOWN, -1, 0, 0);
75 case TRACE_ICONST: /* when it is constant, check second argument */
77 case TRACE_IVAR: /* when second argument is a variable value */
78 case TRACE_ALENGTH: /* or array length, just add the constant */
82 a->constant += b->constant;
84 case TRACE_UNKNOWN: /* when unknown/array ref. return unknown */
86 return create_trace(TRACE_UNKNOWN, -1, 0, 0);
87 case TRACE_ICONST: /* when both are constant, just add them */
88 a->constant += b->constant;
93 case TRACE_IVAR: /* when it is a variable value or array length, */
94 case TRACE_ALENGTH: /* check second argument */
96 case TRACE_IVAR: /* when it is not a constant return unknown */
100 return create_trace(TRACE_UNKNOWN, -1, 0, 0);
101 case TRACE_ICONST: /* when it is a constant, just add it */
102 a->constant += b->constant;
111 /* When the function tracing(...) encounters a neg instruction during its
112 backward scan over the instructions, it trys to identify the source of the
113 argument of this neg function. The following function performs this task.
115 struct Trace* negate(struct Trace* a)
117 switch (a->type) { /* check argument type */
118 case TRACE_IVAR: /* when it is variable/array length value */
120 a->neg = -(a->neg); /* invert negate flag */
121 a->constant = -(a->constant); /* and negate constant */
124 case TRACE_ICONST: /* when it is a constant, negate it */
125 a->constant = -(a->constant);
129 a->type = TRACE_UNKNOWN; /* else return unknown */
136 /* When the function tracing(...) encounters a sub instruction during its backward
137 scan over the instructions, it trys to identify the source of the arguments of
138 this sub function. The following function performs this task, by applaying the
139 negate function on the second argument and then adds the values.
141 struct Trace* sub(struct Trace* a, struct Trace* b)
143 struct Trace *c = negate(b);
148 /* When the function tracing(...) encounters an array length instruction during
149 its backward scan over the instructions, it trys to identify the source of
150 the argument ofthis array length function. The following function performs
153 struct Trace* array_length(struct Trace* a)
155 if (a->type == TRACE_AVAR) /* if argument is an array ref., mark the type */
156 a->type = TRACE_ALENGTH; /* as array length of this array reference */
158 a->type = TRACE_UNKNOWN; /* else it's unknown */
163 /* This function is used to identify the types of operands of an intermediate
164 code instruction.It is needed by functions, that analyze array accesses. If
165 something is stored into or loaded from an array, we have to find out, which
166 array really has been accessed. When a compare instruction is encountered at
167 a loop header, the type of its operands have to be detected to construct
168 dynamic bounds for some variables in the loop. This function returns a struct
169 Trace (see loop.h for more details about this structure). block is the basic
170 block to be examined, index holds the offset of the examined instruction in
171 this block. The arguments are retrieved by using the stack structure, the
172 compilation process sets up. During the backwards scan of the code, it is
173 possible, that other instructions temporaray put or get values from the stack
174 and hide the value, we are interested in below them. The value temp counts
175 the number of values on the stack, the are located beyond the target value.
177 struct Trace* tracing(basicblock *block, int index, int temp)
184 ip = block->iinstr+index;
186 /* printf("TRACING with %d %d %d\n", index, temp, ip->opc);
190 /* nop, nullcheckpop */
191 case ICMD_NOP: /* ... ==> ... */
192 return tracing(block, index-1, temp);
195 case ICMD_NULLCHECKPOP: /* ..., objectref ==> ... */
196 return tracing(block, index-1, temp+1);
205 return tracing(block, index-1, temp-1);
207 return create_trace(TRACE_UNKNOWN, -1, 0, index);
211 if (temp > 0) /* if the target argument is not on top */
212 return tracing(block, index-1, temp-1); /* look further */
214 return create_trace(TRACE_ICONST, -1, ip->val.i, index);
215 break; /* else, return the value, found at this instr. */
222 return tracing(block, index-1, temp-1);
224 return create_trace(TRACE_UNKNOWN, -1, 0, index);
229 return tracing(block, index-1, temp-1);
231 return create_trace(TRACE_IVAR, ip->op1, 0, index);
236 return tracing(block, index-1, temp-1);
238 return create_trace(TRACE_AVAR, ip->op1, 0, index);
246 return tracing(block, index-1, temp+1);
252 return tracing(block, index-1, temp+1);
256 return tracing(block, index-1, temp+2);
261 return tracing(block, index-1, temp-1);
263 return tracing(block, index-1, temp);
266 case ICMD_DUP_X1: /* ..., a, b ==> ..., b, a, b */
268 case 0: /* when looking for top or third element, */
269 case 2: /* just return top element */
270 return tracing(block, index-1, 0);
272 return tracing(block, index-1, 1);
274 return tracing(block, index-1, temp-1);
278 case ICMD_DUP2: /* ..., a, b ==> ..., a, b, a, b */
280 case 0: /* when looking for top or third element */
281 case 2: /* just return top element */
282 return tracing(block, index-1, 0);
283 case 1: /* when looking for second or fourth element*/
284 case 3: /* just return second element */
285 return tracing(block, index-1, 1);
287 return tracing(block, index-1, temp-2);
291 case ICMD_DUP2_X1: /* ..., a, b, c ==> ..., b, c, a, b, c */
295 return tracing(block, index-1, 0);
298 return tracing(block, index-1, 1);
300 return tracing(block, index-1, 2);
302 return tracing(block, index-1, temp-2);
306 case ICMD_DUP_X2: /* ..., a, b, c ==> ..., c, a, b, c */
310 return tracing(block, index-1, 0);
313 return tracing(block, index-1, 1);
315 return tracing(block, index-1, 2);
317 return tracing(block, index-1, temp-2);
321 case ICMD_DUP2_X2: /* .., a, b, c, d ==> ..., c, d, a, b, c, d */
325 return tracing(block, index-1, 0);
328 return tracing(block, index-1, 1);
330 return tracing(block, index-1, 2);
332 return tracing(block, index-1, 3);
334 return tracing(block, index-1, temp-2);
338 case ICMD_SWAP: /* ..., a, b ==> ..., b, a */
341 return tracing(block, index-1, 1);
343 return tracing(block, index-1, 0);
345 return tracing(block, index-1, temp);
349 /* Interger operations */
350 case ICMD_INEG: /* ..., value ==> ..., - value */
352 return tracing(block, index-1, temp);
353 else /* if an inter neg. operation is found, */
354 /* invokethe negate function */
355 return negate(tracing(block, index-1, temp));
358 case ICMD_LNEG: /* ..., value ==> ..., - value */
359 case ICMD_I2L: /* ..., value ==> ..., value */
360 case ICMD_L2I: /* ..., value ==> ..., value */
361 case ICMD_INT2BYTE: /* ..., value ==> ..., value */
362 case ICMD_INT2CHAR: /* ..., value ==> ..., value */
363 case ICMD_INT2SHORT: /* ..., value ==> ..., value */
365 return tracing(block, index-1, temp);
367 return create_trace(TRACE_UNKNOWN, -1, 0, index);
370 case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */
372 return tracing(block, index-1, temp+1);
373 else /* when add is encountered, invoke add func */
374 return add(tracing(block, index-1, 0), tracing(block, index-1, 1));
377 case ICMD_IADDCONST: /* ..., value ==> ..., value + constant */
379 return tracing(block, index-1, temp);
380 else /* when a constant is added, create a */
381 /* constant-trace and use add function */
382 return add(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, ip->val.i, index));
385 case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */
387 return tracing(block, index-1, temp+1);
388 else /* use sub function for sub instructions */
389 return sub(tracing(block, index-1, 1), tracing(block, index-1, 0));
392 case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */
394 return tracing(block, index-1, temp);
396 return sub(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, ip->val.i, index));
399 case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */
400 case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
401 case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
402 case ICMD_LMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
403 case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */
404 case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
405 case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
406 case ICMD_LSHL: /* ..., val1, val2 ==> ..., val1 << val2 */
407 case ICMD_LSHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
408 case ICMD_LUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
409 case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */
411 case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */
413 case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */
416 return tracing(block, index-1, temp+1);
418 return create_trace(TRACE_UNKNOWN, -1, 0, index);
421 case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */
422 case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */
423 case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */
424 case ICMD_LMULCONST: /* ..., value ==> ..., value * constant */
425 case ICMD_IDIVPOW2: /* ..., value ==> ..., value << constant */
426 case ICMD_LDIVPOW2: /* val.i = constant */
427 case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */
428 case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */
429 case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */
430 case ICMD_LSHLCONST: /* ..., value ==> ..., value << constant */
431 case ICMD_LSHRCONST: /* ..., value ==> ..., value >> constant */
432 case ICMD_LUSHRCONST: /* ..., value ==> ..., value >>> constant */
433 case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */
434 case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */
435 case ICMD_IREM0X10001: /* ..., value ==> ..., value % 0x100001 */
436 case ICMD_LANDCONST: /* ..., value ==> ..., value & constant */
437 case ICMD_LREMPOW2: /* ..., value ==> ..., value % constant */
438 case ICMD_LREM0X10001: /* ..., value ==> ..., value % 0x10001 */
439 case ICMD_IORCONST: /* ..., value ==> ..., value | constant */
440 case ICMD_LORCONST: /* ..., value ==> ..., value | constant */
441 case ICMD_IXORCONST: /* ..., value ==> ..., value ^ constant */
442 case ICMD_LXORCONST: /* ..., value ==> ..., value ^ constant */
443 case ICMD_LCMP: /* ..., val1, val2 ==> ..., val1 cmp val2 */
445 return tracing(block, index-1, temp);
447 return create_trace(TRACE_UNKNOWN, -1, 0, index);
450 case ICMD_IINC: /* ..., value ==> ..., value + constant */
451 return tracing(block, index-1, temp);
455 /* floating operations */
456 case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */
457 case ICMD_DADD: /* ..., val1, val2 ==> ..., val1 + val2 */
458 case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
459 case ICMD_DSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
460 case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
461 case ICMD_DMUL: /* ..., val1, val2 ==> ..., val1 *** val2 */
462 case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
463 case ICMD_DDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
464 case ICMD_FREM: /* ..., val1, val2 ==> ..., val1 % val2 */
465 case ICMD_DREM: /* ..., val1, val2 ==> ..., val1 % val2 */
466 case ICMD_FCMPL: /* .., val1, val2 ==> ..., val1 fcmpl val2 */
468 case ICMD_FCMPG: /* .., val1, val2 ==> ..., val1 fcmpg val2 */
471 return tracing(block, index-1, temp+1);
473 return create_trace(TRACE_UNKNOWN, -1, 0, index);
476 case ICMD_FNEG: /* ..., value ==> ..., - value */
477 case ICMD_DNEG: /* ..., value ==> ..., - value */
478 case ICMD_I2F: /* ..., value ==> ..., (float) value */
480 case ICMD_I2D: /* ..., value ==> ..., (double) value */
482 case ICMD_F2I: /* ..., value ==> ..., (int) value */
484 case ICMD_F2L: /* ..., value ==> ..., (long) value */
486 case ICMD_F2D: /* ..., value ==> ..., (double) value */
487 case ICMD_D2F: /* ..., value ==> ..., (double) value */
489 return tracing(block, index-1, temp);
491 return create_trace(TRACE_UNKNOWN, -1, 0, index);
494 /* memory operations */
495 case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., length */
497 return tracing(block, index-1, temp);
499 return array_length(tracing(block, index-1, 0));
502 case ICMD_AALOAD: /* ..., arrayref, index ==> ..., value */
503 case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */
504 case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */
505 case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */
506 case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */
507 case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */
508 case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */
509 case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */
511 return tracing(block, index-1, temp+1);
513 return create_trace(TRACE_UNKNOWN, -1, 0, index);
516 case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */
517 case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */
518 case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */
519 case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */
520 case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */
521 case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */
522 case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */
523 case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */
524 return tracing(block, index-1, temp+3);
527 case ICMD_PUTSTATIC: /* ..., value ==> ... */
528 case ICMD_PUTFIELD: /* ..., value ==> ... */
529 return tracing(block, index-1, temp+1);
532 case ICMD_GETSTATIC: /* ... ==> ..., value */
533 case ICMD_GETFIELD: /* ... ==> ..., value */
535 return tracing(block, index-1, temp-1);
537 return create_trace(TRACE_UNKNOWN, -1, 0, index);
541 /* branch: should not be encountered, but function calls possible */
542 case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */
543 m = ip->val.a; /* get method pointer and */
544 args = ip->op1; /* number of arguments */
545 if (m->returntype != TYPE_VOID)
546 retval = 1; /* if function returns a value, it is on */
547 else /* top of stack */
550 if (temp > 0) /* temp is increased by number of arguments */
551 /* less a possible result value */
552 return tracing(block, index-1, temp+(args-retval));
554 return create_trace(TRACE_UNKNOWN, -1, 0, index);
557 case ICMD_INVOKESPECIAL: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
558 case ICMD_INVOKEVIRTUAL: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
559 case ICMD_INVOKEINTERFACE: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
562 if (m->returntype != TYPE_VOID)
567 if (temp > 0) /* same as above but add 1 for object ref */
568 return tracing(block, index-1, temp+(args-retval+1));
570 return create_trace(TRACE_UNKNOWN, -1, 0, index);
574 case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */
575 case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */
577 return tracing(block, index-1, temp);
579 return create_trace(TRACE_UNKNOWN, -1, 0, index);
582 case ICMD_MULTIANEWARRAY: /* ..., cnt1, [cnt2, ...] ==> ..., arrayref */
583 /* op1 = dimension */
585 if (temp > 0) /* temp increased by number of dimensions */
586 /* minus one for array ref */
587 return tracing(block, index-1, temp+(ip->op1 - 1));
589 return create_trace(TRACE_UNKNOWN, -1, 0, index);
592 case ICMD_BUILTIN3: /* ..., arg1, arg2, arg3 ==> ... */
593 if (ip->op1 != TYPE_VOID)
598 if (temp > 0) /* increase temp by 3 minus possible return */
600 return tracing(block, index-1, temp+(3-retval));
602 return create_trace(TRACE_UNKNOWN, -1, 0, index);
605 case ICMD_BUILTIN2: /* ..., arg1, arg2 ==> ... */
606 if (ip->op1 != TYPE_VOID)
611 return tracing(block, index-1, temp+(2-retval));
613 return create_trace(TRACE_UNKNOWN, -1, 0, index);
616 case ICMD_BUILTIN1: /* ..., arg1 ==> ... */
617 if (ip->op1 != TYPE_VOID)
622 return tracing(block, index-1, temp+(1-retval));
624 return create_trace(TRACE_UNKNOWN, -1, 0, index);
629 return create_trace(TRACE_UNKNOWN, -1, 0, index);
633 return create_trace(TRACE_UNKNOWN, -1, 0, index);
637 * These are local overrides for various environment variables in Emacs.
638 * Please do not remove this and leave it at the end of the file, where
639 * Emacs will automagically detect them.
640 * ---------------------------------------------------------------------
643 * indent-tabs-mode: t