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,
37 #include "mm/memory.h"
38 #include "vm/builtin.h"
39 #include "vm/resolve.h"
40 #include "vm/jit/loop/loop.h"
41 #include "vm/jit/loop/tracing.h"
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 Trace* create_trace(int type, int var, int constant, int nr)
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 Trace* add(Trace* a, 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 Trace* negate(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 Trace* sub(Trace* a, Trace* b)
173 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 Trace* array_length(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 /* tracing *********************************************************************
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,
199 which array really has been accessed. When a compare instruction is
200 encountered at a loop header, the type of its operands have to be detected
201 to construct dynamic bounds for some variables in the loop. This function
202 returns a struct Trace (see loop.h for more details about this structure).
203 block is the basic block to be examined, index holds the offset of the
204 examined instruction in this block. The arguments are retrieved by using
205 the stack structure, the compilation process sets up. During the backwards
206 scan of the code, it is possible, that other instructions temporary put or
207 get values from the stack and hide the value, we are interested in below
208 them. The value temp counts the number of values on the stack, the are
209 located beyond the target value.
211 *******************************************************************************/
213 Trace* tracing(basicblock *block, int index, int temp)
217 builtintable_entry *bte;
223 iptr = block->iinstr + index;
227 /* nop, nullcheckpop */
228 case ICMD_NOP: /* ... ==> ... */
229 return tracing(block, index - 1, temp);
232 case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */
233 return tracing(block, index-1, temp);
242 return tracing(block, index - 1, temp - 1);
244 return create_trace(TRACE_UNKNOWN, -1, 0, index);
248 if (temp > 0) /* if the target argument is not on top */
249 return tracing(block, index-1, temp-1); /* look further */
251 return create_trace(TRACE_ICONST, -1, iptr->val.i, index);
252 break; /* else, return the value, found at this instr. */
259 return tracing(block, index-1, temp-1);
261 return create_trace(TRACE_UNKNOWN, -1, 0, index);
266 return tracing(block, index-1, temp-1);
268 return create_trace(TRACE_IVAR, iptr->op1, 0, index);
273 return tracing(block, index-1, temp-1);
275 return create_trace(TRACE_AVAR, iptr->op1, 0, index);
283 return tracing(block, index-1, temp+1);
289 return tracing(block, index-1, temp+1);
293 return tracing(block, index-1, temp+2);
298 return tracing(block, index-1, temp-1);
300 return tracing(block, index-1, temp);
303 case ICMD_DUP_X1: /* ..., a, b ==> ..., b, a, b */
305 case 0: /* when looking for top or third element, */
306 case 2: /* just return top element */
307 return tracing(block, index-1, 0);
309 return tracing(block, index-1, 1);
311 return tracing(block, index-1, temp-1);
315 case ICMD_DUP2: /* ..., a, b ==> ..., a, b, a, b */
317 case 0: /* when looking for top or third element */
318 case 2: /* just return top element */
319 return tracing(block, index-1, 0);
320 case 1: /* when looking for second or fourth element*/
321 case 3: /* just return second element */
322 return tracing(block, index-1, 1);
324 return tracing(block, index-1, temp-2);
328 case ICMD_DUP2_X1: /* ..., a, b, c ==> ..., b, c, a, b, c */
332 return tracing(block, index-1, 0);
335 return tracing(block, index-1, 1);
337 return tracing(block, index-1, 2);
339 return tracing(block, index-1, temp-2);
343 case ICMD_DUP_X2: /* ..., a, b, c ==> ..., c, a, b, c */
347 return tracing(block, index-1, 0);
350 return tracing(block, index-1, 1);
352 return tracing(block, index-1, 2);
354 return tracing(block, index-1, temp-2);
358 case ICMD_DUP2_X2: /* .., a, b, c, d ==> ..., c, d, a, b, c, d */
362 return tracing(block, index-1, 0);
365 return tracing(block, index-1, 1);
367 return tracing(block, index-1, 2);
369 return tracing(block, index-1, 3);
371 return tracing(block, index-1, temp-2);
375 case ICMD_SWAP: /* ..., a, b ==> ..., b, a */
378 return tracing(block, index-1, 1);
380 return tracing(block, index-1, 0);
382 return tracing(block, index-1, temp);
386 /* Interger operations */
387 case ICMD_INEG: /* ..., value ==> ..., - value */
389 return tracing(block, index-1, temp);
390 else /* if an inter neg. operation is found, */
391 /* invokethe negate function */
392 return negate(tracing(block, index-1, temp));
395 case ICMD_LNEG: /* ..., value ==> ..., - value */
396 case ICMD_I2L: /* ..., value ==> ..., value */
397 case ICMD_L2I: /* ..., value ==> ..., value */
398 case ICMD_INT2BYTE: /* ..., value ==> ..., value */
399 case ICMD_INT2CHAR: /* ..., value ==> ..., value */
400 case ICMD_INT2SHORT: /* ..., value ==> ..., value */
402 return tracing(block, index-1, temp);
404 return create_trace(TRACE_UNKNOWN, -1, 0, index);
407 case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */
409 return tracing(block, index-1, temp+1);
410 else /* when add is encountered, invoke add func */
411 return add(tracing(block, index-1, 0), tracing(block, index-1, 1));
414 case ICMD_IADDCONST: /* ..., value ==> ..., value + constant */
416 return tracing(block, index-1, temp);
417 else /* when a constant is added, create a */
418 /* constant-trace and use add function */
419 return add(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, iptr->val.i, index));
422 case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */
424 return tracing(block, index-1, temp+1);
425 else /* use sub function for sub instructions */
426 return sub(tracing(block, index-1, 1), tracing(block, index-1, 0));
429 case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */
431 return tracing(block, index-1, temp);
433 return sub(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, iptr->val.i, index));
436 case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */
437 case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
438 case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
439 case ICMD_LMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
440 case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */
441 case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
442 case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
443 case ICMD_LSHL: /* ..., val1, val2 ==> ..., val1 << val2 */
444 case ICMD_LSHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
445 case ICMD_LUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
446 case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */
448 case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */
450 case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */
453 return tracing(block, index-1, temp+1);
455 return create_trace(TRACE_UNKNOWN, -1, 0, index);
458 case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */
459 case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */
460 case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */
461 case ICMD_LMULCONST: /* ..., value ==> ..., value * constant */
462 case ICMD_IDIVPOW2: /* ..., value ==> ..., value << constant */
463 case ICMD_LDIVPOW2: /* val.i = constant */
464 case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */
465 case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */
466 case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */
467 case ICMD_LSHLCONST: /* ..., value ==> ..., value << constant */
468 case ICMD_LSHRCONST: /* ..., value ==> ..., value >> constant */
469 case ICMD_LUSHRCONST: /* ..., value ==> ..., value >>> constant */
470 case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */
471 case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */
472 case ICMD_LANDCONST: /* ..., value ==> ..., value & constant */
473 case ICMD_LREMPOW2: /* ..., value ==> ..., value % constant */
474 case ICMD_IORCONST: /* ..., value ==> ..., value | constant */
475 case ICMD_LORCONST: /* ..., value ==> ..., value | constant */
476 case ICMD_IXORCONST: /* ..., value ==> ..., value ^ constant */
477 case ICMD_LXORCONST: /* ..., value ==> ..., value ^ constant */
478 case ICMD_LCMP: /* ..., val1, val2 ==> ..., val1 cmp val2 */
480 return tracing(block, index-1, temp);
482 return create_trace(TRACE_UNKNOWN, -1, 0, index);
485 case ICMD_IINC: /* ..., value ==> ..., value + constant */
486 return tracing(block, index-1, temp);
490 /* floating operations */
491 case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */
492 case ICMD_DADD: /* ..., val1, val2 ==> ..., val1 + val2 */
493 case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
494 case ICMD_DSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
495 case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
496 case ICMD_DMUL: /* ..., val1, val2 ==> ..., val1 *** val2 */
497 case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
498 case ICMD_DDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
499 case ICMD_FREM: /* ..., val1, val2 ==> ..., val1 % val2 */
500 case ICMD_DREM: /* ..., val1, val2 ==> ..., val1 % val2 */
501 case ICMD_FCMPL: /* .., val1, val2 ==> ..., val1 fcmpl val2 */
503 case ICMD_FCMPG: /* .., val1, val2 ==> ..., val1 fcmpg val2 */
506 return tracing(block, index-1, temp+1);
508 return create_trace(TRACE_UNKNOWN, -1, 0, index);
511 case ICMD_FNEG: /* ..., value ==> ..., - value */
512 case ICMD_DNEG: /* ..., value ==> ..., - value */
513 case ICMD_I2F: /* ..., value ==> ..., (float) value */
515 case ICMD_I2D: /* ..., value ==> ..., (double) value */
517 case ICMD_F2I: /* ..., value ==> ..., (int) value */
519 case ICMD_F2L: /* ..., value ==> ..., (long) value */
521 case ICMD_F2D: /* ..., value ==> ..., (double) value */
522 case ICMD_D2F: /* ..., value ==> ..., (double) value */
524 return tracing(block, index-1, temp);
526 return create_trace(TRACE_UNKNOWN, -1, 0, index);
529 /* memory operations */
530 case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., length */
532 return tracing(block, index-1, temp);
534 return array_length(tracing(block, index-1, 0));
537 case ICMD_AALOAD: /* ..., arrayref, index ==> ..., value */
538 case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */
539 case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */
540 case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */
541 case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */
542 case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */
543 case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */
544 case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */
546 return tracing(block, index-1, temp+1);
548 return create_trace(TRACE_UNKNOWN, -1, 0, index);
551 case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */
552 case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */
553 case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */
554 case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */
555 case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */
556 case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */
557 case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */
558 case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */
559 return tracing(block, index-1, temp+3);
562 case ICMD_PUTSTATIC: /* ..., value ==> ... */
563 case ICMD_PUTFIELD: /* ..., value ==> ... */
564 return tracing(block, index - 1, temp + 1);
567 case ICMD_GETSTATIC: /* ... ==> ..., value */
568 case ICMD_GETFIELD: /* ... ==> ..., value */
570 return tracing(block, index-1, temp - 1);
572 return create_trace(TRACE_UNKNOWN, -1, 0, index);
576 /* branch: should not be encountered, but function calls possible */
578 case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */
579 case ICMD_INVOKESPECIAL: /* ..., objectref, [arg1, [arg2 ...]] ==> . */
580 case ICMD_INVOKEVIRTUAL:
581 case ICMD_INVOKEINTERFACE:
582 INSTRUCTION_GET_METHODDESC(iptr,md);
584 args = md->paramcount; /* number of arguments */
586 if (md->returntype.type != TYPE_VOID)
587 retval = 1; /* if function returns a value, it is on */
588 else /* top of stack */
591 if (temp > 0) /* temp is increased by number of */
592 /* arguments a possible result value */
593 return tracing(block, index - 1, temp + (args - retval));
595 return create_trace(TRACE_UNKNOWN, -1, 0, index);
601 case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */
602 case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */
604 return tracing(block, index-1, temp);
606 return create_trace(TRACE_UNKNOWN, -1, 0, index);
609 case ICMD_MULTIANEWARRAY: /* ..., cnt1, [cnt2, ...] ==> ..., arrayref */
610 /* op1 = dimension */
612 if (temp > 0) /* temp increased by number of dimensions */
613 /* minus one for array ref */
614 return tracing(block, index - 1, temp + (iptr->op1 - 1));
616 return create_trace(TRACE_UNKNOWN, -1, 0, index);
619 case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */
622 args = md->paramcount;
623 if (md->returntype.type != TYPE_VOID)
628 if (temp > 0) /* temp is increased by number of */
629 /* arguments less a possible result value */
630 return tracing(block, index - 1, temp + (args - retval));
632 return create_trace(TRACE_UNKNOWN, -1, 0, index);
639 return create_trace(TRACE_UNKNOWN, -1, 0, index);
644 return create_trace(TRACE_UNKNOWN, -1, 0, index);
649 * These are local overrides for various environment variables in Emacs.
650 * Please do not remove this and leave it at the end of the file, where
651 * Emacs will automagically detect them.
652 * ---------------------------------------------------------------------
655 * indent-tabs-mode: t