1 /* vm/jit/loop/tracing.c - trace functions
3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, 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., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
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 4862 2006-04-30 15:58:53Z edwin $
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 builtintable_entry *bte;
225 iptr = block->iinstr + index;
229 /* nop, nullcheckpop */
230 case ICMD_NOP: /* ... ==> ... */
231 return tracing(block, index - 1, temp);
234 case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */
235 return tracing(block, index-1, temp);
244 return tracing(block, index - 1, temp - 1);
246 return create_trace(TRACE_UNKNOWN, -1, 0, index);
250 if (temp > 0) /* if the target argument is not on top */
251 return tracing(block, index-1, temp-1); /* look further */
253 return create_trace(TRACE_ICONST, -1, iptr->val.i, index);
254 break; /* else, return the value, found at this instr. */
261 return tracing(block, index-1, temp-1);
263 return create_trace(TRACE_UNKNOWN, -1, 0, index);
268 return tracing(block, index-1, temp-1);
270 return create_trace(TRACE_IVAR, iptr->op1, 0, index);
275 return tracing(block, index-1, temp-1);
277 return create_trace(TRACE_AVAR, iptr->op1, 0, index);
285 return tracing(block, index-1, temp+1);
291 return tracing(block, index-1, temp+1);
295 return tracing(block, index-1, temp+2);
300 return tracing(block, index-1, temp-1);
302 return tracing(block, index-1, temp);
305 case ICMD_DUP_X1: /* ..., a, b ==> ..., b, a, b */
307 case 0: /* when looking for top or third element, */
308 case 2: /* just return top element */
309 return tracing(block, index-1, 0);
311 return tracing(block, index-1, 1);
313 return tracing(block, index-1, temp-1);
317 case ICMD_DUP2: /* ..., a, b ==> ..., a, b, a, b */
319 case 0: /* when looking for top or third element */
320 case 2: /* just return top element */
321 return tracing(block, index-1, 0);
322 case 1: /* when looking for second or fourth element*/
323 case 3: /* just return second element */
324 return tracing(block, index-1, 1);
326 return tracing(block, index-1, temp-2);
330 case ICMD_DUP2_X1: /* ..., a, b, c ==> ..., b, c, a, b, c */
334 return tracing(block, index-1, 0);
337 return tracing(block, index-1, 1);
339 return tracing(block, index-1, 2);
341 return tracing(block, index-1, temp-2);
345 case ICMD_DUP_X2: /* ..., a, b, c ==> ..., c, a, b, c */
349 return tracing(block, index-1, 0);
352 return tracing(block, index-1, 1);
354 return tracing(block, index-1, 2);
356 return tracing(block, index-1, temp-2);
360 case ICMD_DUP2_X2: /* .., a, b, c, d ==> ..., c, d, a, b, c, d */
364 return tracing(block, index-1, 0);
367 return tracing(block, index-1, 1);
369 return tracing(block, index-1, 2);
371 return tracing(block, index-1, 3);
373 return tracing(block, index-1, temp-2);
377 case ICMD_SWAP: /* ..., a, b ==> ..., b, a */
380 return tracing(block, index-1, 1);
382 return tracing(block, index-1, 0);
384 return tracing(block, index-1, temp);
388 /* Interger operations */
389 case ICMD_INEG: /* ..., value ==> ..., - value */
391 return tracing(block, index-1, temp);
392 else /* if an inter neg. operation is found, */
393 /* invokethe negate function */
394 return negate(tracing(block, index-1, temp));
397 case ICMD_LNEG: /* ..., value ==> ..., - value */
398 case ICMD_I2L: /* ..., value ==> ..., value */
399 case ICMD_L2I: /* ..., value ==> ..., value */
400 case ICMD_INT2BYTE: /* ..., value ==> ..., value */
401 case ICMD_INT2CHAR: /* ..., value ==> ..., value */
402 case ICMD_INT2SHORT: /* ..., value ==> ..., value */
404 return tracing(block, index-1, temp);
406 return create_trace(TRACE_UNKNOWN, -1, 0, index);
409 case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */
411 return tracing(block, index-1, temp+1);
412 else /* when add is encountered, invoke add func */
413 return add(tracing(block, index-1, 0), tracing(block, index-1, 1));
416 case ICMD_IADDCONST: /* ..., value ==> ..., value + constant */
418 return tracing(block, index-1, temp);
419 else /* when a constant is added, create a */
420 /* constant-trace and use add function */
421 return add(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, iptr->val.i, index));
424 case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */
426 return tracing(block, index-1, temp+1);
427 else /* use sub function for sub instructions */
428 return sub(tracing(block, index-1, 1), tracing(block, index-1, 0));
431 case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */
433 return tracing(block, index-1, temp);
435 return sub(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, iptr->val.i, index));
438 case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */
439 case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
440 case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
441 case ICMD_LMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
442 case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */
443 case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
444 case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
445 case ICMD_LSHL: /* ..., val1, val2 ==> ..., val1 << val2 */
446 case ICMD_LSHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
447 case ICMD_LUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
448 case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */
450 case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */
452 case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */
455 return tracing(block, index-1, temp+1);
457 return create_trace(TRACE_UNKNOWN, -1, 0, index);
460 case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */
461 case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */
462 case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */
463 case ICMD_LMULCONST: /* ..., value ==> ..., value * constant */
464 case ICMD_IDIVPOW2: /* ..., value ==> ..., value << constant */
465 case ICMD_LDIVPOW2: /* val.i = constant */
466 case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */
467 case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */
468 case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */
469 case ICMD_LSHLCONST: /* ..., value ==> ..., value << constant */
470 case ICMD_LSHRCONST: /* ..., value ==> ..., value >> constant */
471 case ICMD_LUSHRCONST: /* ..., value ==> ..., value >>> constant */
472 case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */
473 case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */
474 case ICMD_LANDCONST: /* ..., value ==> ..., value & constant */
475 case ICMD_LREMPOW2: /* ..., value ==> ..., value % constant */
476 case ICMD_IORCONST: /* ..., value ==> ..., value | constant */
477 case ICMD_LORCONST: /* ..., value ==> ..., value | constant */
478 case ICMD_IXORCONST: /* ..., value ==> ..., value ^ constant */
479 case ICMD_LXORCONST: /* ..., value ==> ..., value ^ constant */
480 case ICMD_LCMP: /* ..., val1, val2 ==> ..., val1 cmp val2 */
482 return tracing(block, index-1, temp);
484 return create_trace(TRACE_UNKNOWN, -1, 0, index);
487 case ICMD_IINC: /* ..., value ==> ..., value + constant */
488 return tracing(block, index-1, temp);
492 /* floating operations */
493 case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */
494 case ICMD_DADD: /* ..., val1, val2 ==> ..., val1 + val2 */
495 case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
496 case ICMD_DSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
497 case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
498 case ICMD_DMUL: /* ..., val1, val2 ==> ..., val1 *** val2 */
499 case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
500 case ICMD_DDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
501 case ICMD_FREM: /* ..., val1, val2 ==> ..., val1 % val2 */
502 case ICMD_DREM: /* ..., val1, val2 ==> ..., val1 % val2 */
503 case ICMD_FCMPL: /* .., val1, val2 ==> ..., val1 fcmpl val2 */
505 case ICMD_FCMPG: /* .., val1, val2 ==> ..., val1 fcmpg val2 */
508 return tracing(block, index-1, temp+1);
510 return create_trace(TRACE_UNKNOWN, -1, 0, index);
513 case ICMD_FNEG: /* ..., value ==> ..., - value */
514 case ICMD_DNEG: /* ..., value ==> ..., - value */
515 case ICMD_I2F: /* ..., value ==> ..., (float) value */
517 case ICMD_I2D: /* ..., value ==> ..., (double) value */
519 case ICMD_F2I: /* ..., value ==> ..., (int) value */
521 case ICMD_F2L: /* ..., value ==> ..., (long) value */
523 case ICMD_F2D: /* ..., value ==> ..., (double) value */
524 case ICMD_D2F: /* ..., value ==> ..., (double) value */
526 return tracing(block, index-1, temp);
528 return create_trace(TRACE_UNKNOWN, -1, 0, index);
531 /* memory operations */
532 case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., length */
534 return tracing(block, index-1, temp);
536 return array_length(tracing(block, index-1, 0));
539 case ICMD_AALOAD: /* ..., arrayref, index ==> ..., value */
540 case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */
541 case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */
542 case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */
543 case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */
544 case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */
545 case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */
546 case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */
548 return tracing(block, index-1, temp+1);
550 return create_trace(TRACE_UNKNOWN, -1, 0, index);
553 case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */
554 case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */
555 case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */
556 case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */
557 case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */
558 case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */
559 case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */
560 case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */
561 return tracing(block, index-1, temp+3);
564 case ICMD_PUTSTATIC: /* ..., value ==> ... */
565 case ICMD_PUTFIELD: /* ..., value ==> ... */
566 return tracing(block, index - 1, temp + 1);
569 case ICMD_GETSTATIC: /* ... ==> ..., value */
570 case ICMD_GETFIELD: /* ... ==> ..., value */
572 return tracing(block, index-1, temp - 1);
574 return create_trace(TRACE_UNKNOWN, -1, 0, index);
578 /* branch: should not be encountered, but function calls possible */
580 case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */
581 case ICMD_INVOKESPECIAL: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
582 case ICMD_INVOKEVIRTUAL:
583 case ICMD_INVOKEINTERFACE:
584 INSTRUCTION_GET_METHODDESC(iptr,md);
586 args = md->paramcount; /* number of arguments */
588 if (md->returntype.type != TYPE_VOID)
589 retval = 1; /* if function returns a value, it is on */
590 else /* top of stack */
593 if (temp > 0) /* temp is increased by number of */
594 /* arguments a possible result value */
595 return tracing(block, index - 1, temp + (args - retval));
597 return create_trace(TRACE_UNKNOWN, -1, 0, index);
603 case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */
604 case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */
606 return tracing(block, index-1, temp);
608 return create_trace(TRACE_UNKNOWN, -1, 0, index);
611 case ICMD_MULTIANEWARRAY: /* ..., cnt1, [cnt2, ...] ==> ..., arrayref */
612 /* op1 = dimension */
614 if (temp > 0) /* temp increased by number of dimensions */
615 /* minus one for array ref */
616 return tracing(block, index - 1, temp + (iptr->op1 - 1));
618 return create_trace(TRACE_UNKNOWN, -1, 0, index);
621 case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */
624 args = md->paramcount;
625 if (md->returntype.type != TYPE_VOID)
630 if (temp > 0) /* temp is increased by number of */
631 /* arguments less a possible result value */
632 return tracing(block, index - 1, temp + (args - retval));
634 return create_trace(TRACE_UNKNOWN, -1, 0, index);
641 return create_trace(TRACE_UNKNOWN, -1, 0, index);
646 return create_trace(TRACE_UNKNOWN, -1, 0, index);
651 * These are local overrides for various environment variables in Emacs.
652 * Please do not remove this and leave it at the end of the file, where
653 * Emacs will automagically detect them.
654 * ---------------------------------------------------------------------
657 * indent-tabs-mode: t