d227fb44ea2502b7ecf432d390931e0072360ee8
[cacao.git] / src / vm / jit / loop / tracing.c
1 /* vm/jit/loop/tracing.c - trace functions
2
3    Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
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.
14
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.
19
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
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Christopher Kruegel
28
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,
32    int) below.
33
34    $Id: tracing.c 3617 2005-11-07 18:39:10Z twisti $
35
36 */
37
38
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"
44
45
46 /*      Test function -> will be removed in final release
47 */
48 void printTraceResult(struct Trace *p)
49 {
50         printf("TRACE: ");
51
52         switch (p->type) {
53         case TRACE_UNKNOWN:
54                 printf("\tUnknown");
55                 break;
56         case TRACE_ICONST:
57                 printf("\tconst - %d", p->constant);
58                 break;
59         case TRACE_ALENGTH:
60                 printf("\tarray - (%d)%d - %d", p->neg, p->var, p->constant);
61                 break;
62         case TRACE_IVAR:
63                 printf("\tivar - (%d)%d - %d", p->neg, p->var, p->constant);
64                 break;
65         case TRACE_AVAR:
66                 printf("\tavar - %d", p->var);
67                 break;
68                 }
69         
70         printf("\n");
71 }
72
73     
74 /*      A function that creates a new trace structure and initializes its values
75 */
76 Trace* create_trace(int type, int var, int constant, int nr)
77 {
78         Trace *t;
79
80         t = DNEW(Trace);
81
82         t->type = type;
83
84         t->neg = 1;
85         t->var = var;
86         t->nr = nr;
87
88         t->constant = constant;
89
90         return t;
91 }
92
93
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.
97 */
98 Trace* add(Trace* a, Trace* b)
99 {
100         switch (a->type) {                      /* check the first argument of add. when it             */
101         case TRACE_UNKNOWN:                     /* is unknown or array-address, return unknown  */
102         case TRACE_AVAR:
103                 return create_trace(TRACE_UNKNOWN, -1, 0, 0);
104
105         case TRACE_ICONST:                      /* when it is constant, check second argument   */
106                 switch (b->type) {
107                 case TRACE_IVAR:                        /* when second argument is a variable value */
108                 case TRACE_ALENGTH:                     /* or array length, just add the constant       */
109                         a->type = b->type;
110                         a->var  = b->var;
111                         a->neg  = b->neg;
112                         a->constant += b->constant;
113                         break;
114                 case TRACE_UNKNOWN:                     /* when unknown/array ref. return unknown       */
115                 case TRACE_AVAR:
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;
119                         break;
120                         }
121                 break;
122
123         case TRACE_IVAR:                        /* when it is a variable value or array length, */
124         case TRACE_ALENGTH:                     /* check second argument                                                */
125                 switch (b->type) {
126                 case TRACE_IVAR:                        /* when it is not a constant return unknown     */
127                 case TRACE_ALENGTH:
128                 case TRACE_UNKNOWN:
129                 case TRACE_AVAR:
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;
133                         break;
134                         }
135                 break;
136                 }
137
138         return a;
139 }
140
141
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.
145 */
146 Trace* negate(Trace* a)
147 {
148         switch (a->type) {                              /* check argument type                                          */
149         case TRACE_IVAR:                                /* when it is variable/array length value       */
150         case TRACE_ALENGTH:                                     
151                 a->neg = -(a->neg);                             /* invert negate flag                                   */
152                 a->constant = -(a->constant);   /* and negate constant                                  */
153                 break;
154         
155         case TRACE_ICONST:                              /* when it is a constant, negate it                     */
156                 a->constant = -(a->constant);
157                 break;
158
159         default:
160                 a->type = TRACE_UNKNOWN;        /* else return unknown                                          */
161                 break;
162                 }
163
164   return a;
165 }
166
167
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.
172 */
173 Trace* sub(Trace* a, Trace* b)
174 {
175         Trace *c = negate(b);
176         return add(a, c);
177 }
178
179
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 
183         this task.
184 */
185 Trace* array_length(Trace* a)
186 {
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      */
189         else
190                 a->type = TRACE_UNKNOWN;        /* else it's unknown                                    */
191
192         return a;
193 }
194
195
196 /* tracing *********************************************************************
197
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.
212
213 *******************************************************************************/
214
215 Trace* tracing(basicblock *block, int index, int temp)
216 {
217         instruction        *iptr;
218         methodinfo         *m;
219         unresolved_method  *um;
220         builtintable_entry *bte;
221         methoddesc         *md;
222         s4                  args;
223         s4                  retval;
224
225         if (index >= 0) {
226                 iptr = block->iinstr + index;
227
228                 switch (iptr->opc) {
229                 
230                 /* nop, nullcheckpop                                                  */
231                 case ICMD_NOP:              /* ...  ==> ...                           */
232                         return tracing(block, index - 1, temp);
233                         break;
234       
235                 case ICMD_CHECKNULL:        /* ..., objectref  ==> ..., objectref     */
236                         return tracing(block, index-1, temp);
237                         break;
238
239                 /* Constants                                                          */
240                 case ICMD_LCONST:                               
241                 case ICMD_DCONST:
242                 case ICMD_FCONST:
243                 case ICMD_ACONST:
244                         if (temp > 0)                           
245                                 return tracing(block, index - 1, temp - 1);
246                         else
247                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
248                         break;                                          
249
250                 case ICMD_ICONST:
251                         if (temp > 0)           /* if the target argument is not on top                 */
252                                 return tracing(block, index-1, temp-1); /* look further                 */
253                         else
254                                 return create_trace(TRACE_ICONST, -1, iptr->val.i, index);
255                         break;                          /* else, return the value, found at this instr. */
256
257                 /* Load/Store                                                                                                                   */
258         case ICMD_LLOAD:                
259                 case ICMD_DLOAD:    
260                 case ICMD_FLOAD:
261                         if (temp > 0)
262                                 return tracing(block, index-1, temp-1);
263                         else
264                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
265                         break;
266     
267                 case ICMD_ILOAD:
268                         if (temp > 0)
269                                 return tracing(block, index-1, temp-1);
270                     else
271                                 return create_trace(TRACE_IVAR, iptr->op1, 0, index);
272                         break;
273
274                 case ICMD_ALOAD:    
275                         if (temp > 0)
276                                 return tracing(block, index-1, temp-1);
277                         else
278                                 return create_trace(TRACE_AVAR, iptr->op1, 0, index);                   
279                         break;
280                 
281                 case ICMD_LSTORE:    
282                 case ICMD_DSTORE:    
283                 case ICMD_FSTORE:
284                 case ICMD_ISTORE:
285                 case ICMD_ASTORE:    
286                         return tracing(block, index-1, temp+1);
287                         break;
288         
289
290                 /* pop/dup/swap                                                                                                                 */
291                 case ICMD_POP:      
292                         return tracing(block, index-1, temp+1);
293                         break;
294      
295                 case ICMD_POP2:  
296                         return tracing(block, index-1, temp+2);
297                         break;
298
299                 case ICMD_DUP:
300                         if (temp > 0)
301                                 return tracing(block, index-1, temp-1);
302                         else
303                                 return tracing(block, index-1, temp);
304                         break;
305
306                 case ICMD_DUP_X1:                       /* ..., a, b ==> ..., b, a, b                           */
307                         switch (temp) {
308                         case 0:                                 /* when looking for top or third element,       */
309                         case 2:                                 /* just return top element                                      */
310                                 return tracing(block, index-1, 0);
311                         case 1:
312                                 return tracing(block, index-1, 1);
313                         default:
314                                 return tracing(block, index-1, temp-1);
315                                 }
316                         break;
317
318                 case ICMD_DUP2:                         /* ..., a, b ==> ..., a, b, a, b                        */
319                         switch (temp) { 
320                         case 0:                                 /* when looking for top or third element        */
321                         case 2:                                 /* just return top element                                      */
322                                 return tracing(block, index-1, 0);
323                         case 1:                                 /* when looking for second or fourth element*/
324                         case 3:                                 /* just return second element                           */
325                                 return tracing(block, index-1, 1);
326                         default:
327                                 return tracing(block, index-1, temp-2);
328                                 }
329                         break;
330
331                 case ICMD_DUP2_X1:                      /* ..., a, b, c ==> ..., b, c, a, b, c          */
332                         switch (temp) {
333                         case 0:
334                         case 3:
335                                 return tracing(block, index-1, 0);
336                         case 1:
337                         case 4:
338                                 return tracing(block, index-1, 1);
339                         case 2:
340                                 return tracing(block, index-1, 2);
341                         default:
342                                 return tracing(block, index-1, temp-2);
343                                 }
344                         break;
345
346                 case ICMD_DUP_X2:                       /* ..., a, b, c ==> ..., c, a, b, c                     */
347                         switch (temp) {    
348                         case 0:
349                         case 3:
350                                 return tracing(block, index-1, 0);
351                         case 1:
352                         case 4:
353                                 return tracing(block, index-1, 1);
354                         case 2:
355                                 return tracing(block, index-1, 2);
356                         default:
357                                 return tracing(block, index-1, temp-2);
358                                 }
359                         break;
360
361                 case ICMD_DUP2_X2:                      /* .., a, b, c, d ==> ..., c, d, a, b, c, d     */
362                         switch (temp) {
363                         case 0:
364                         case 4:
365                                 return tracing(block, index-1, 0);
366                         case 1:
367                         case 5:
368                                 return tracing(block, index-1, 1);
369                         case 2:
370                                 return tracing(block, index-1, 2);
371                         case 3:
372                                 return tracing(block, index-1, 3);
373                         default:
374                                 return tracing(block, index-1, temp-2);
375                                 }
376                         break;
377
378                 case ICMD_SWAP:                         /* ..., a, b ==> ..., b, a                                      */
379                         switch (temp) {
380                         case 0:
381                                 return tracing(block, index-1, 1);
382                         case 1:
383                                 return tracing(block, index-1, 0);
384                         default:
385                                 return tracing(block, index-1, temp);
386                                 }
387                         break;
388       
389                 /* Interger operations                                                                                                  */
390             case ICMD_INEG:                             /* ..., value  ==> ..., - value                         */
391                         if (temp > 0)
392                                 return tracing(block, index-1, temp);
393                         else                                    /* if an inter neg. operation is found,         */
394                                                                         /* invokethe negate function                            */
395                                 return negate(tracing(block, index-1, temp));
396                         break;
397
398                 case ICMD_LNEG:                         /* ..., value  ==> ..., - value                         */
399                 case ICMD_I2L:                          /* ..., value  ==> ..., value                           */
400                 case ICMD_L2I:                          /* ..., value  ==> ..., value                           */
401                 case ICMD_INT2BYTE:                     /* ..., value  ==> ..., value                           */
402                 case ICMD_INT2CHAR:                     /* ..., value  ==> ..., value                           */
403                 case ICMD_INT2SHORT:            /* ..., value  ==> ..., value                           */
404                         if (temp > 0)
405                                 return tracing(block, index-1, temp);
406                         else
407                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
408                         break;
409
410                 case ICMD_IADD:                         /* ..., val1, val2  ==> ..., val1 + val2        */
411                         if (temp > 0)
412                                 return tracing(block, index-1, temp+1);
413                         else                                    /* when add is encountered, invoke add func     */
414                                 return add(tracing(block, index-1, 0), tracing(block, index-1, 1));
415                         break;
416
417                 case ICMD_IADDCONST:            /* ..., value  ==> ..., value + constant        */
418                         if (temp > 0)
419                                 return tracing(block, index-1, temp);
420                         else                                    /* when a constant is added, create a           */
421                                                                         /* constant-trace and use add function          */
422                                 return add(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, iptr->val.i, index));
423                         break;
424
425                 case ICMD_ISUB:                         /* ..., val1, val2  ==> ..., val1 - val2        */
426                         if (temp > 0)
427                                 return tracing(block, index-1, temp+1);
428                         else                                    /* use sub function for sub instructions        */
429                                 return sub(tracing(block, index-1, 1), tracing(block, index-1, 0));
430                         break;
431
432                 case ICMD_ISUBCONST:            /* ..., value  ==> ..., value + constant        */
433                         if (temp > 0)
434                                 return tracing(block, index-1, temp);
435                         else
436                                 return sub(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, iptr->val.i, index));
437                         break;
438
439                 case ICMD_LADD:                         /* ..., val1, val2  ==> ..., val1 + val2        */
440                 case ICMD_LSUB:                         /* ..., val1, val2  ==> ..., val1 - val2        */
441                 case ICMD_IMUL:                         /* ..., val1, val2  ==> ..., val1 * val2        */
442                 case ICMD_LMUL:                         /* ..., val1, val2  ==> ..., val1 * val2        */
443                 case ICMD_ISHL:                         /* ..., val1, val2  ==> ..., val1 << val2       */
444                 case ICMD_ISHR:                         /* ..., val1, val2  ==> ..., val1 >> val2       */
445                 case ICMD_IUSHR:                        /* ..., val1, val2  ==> ..., val1 >>> val2      */
446                 case ICMD_LSHL:                         /* ..., val1, val2  ==> ..., val1 << val2       */
447                 case ICMD_LSHR:                         /* ..., val1, val2  ==> ..., val1 >> val2       */
448                 case ICMD_LUSHR:                        /* ..., val1, val2  ==> ..., val1 >>> val2      */
449                 case ICMD_IAND:                         /* ..., val1, val2  ==> ..., val1 & val2        */
450                 case ICMD_LAND:  
451                 case ICMD_IOR:                          /* ..., val1, val2  ==> ..., val1 | val2        */
452                 case ICMD_LOR:
453                 case ICMD_IXOR:                         /* ..., val1, val2  ==> ..., val1 ^ val2        */
454                 case ICMD_LXOR:
455                         if (temp > 0)
456                                 return tracing(block, index-1, temp+1);
457                         else
458                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
459                         break;
460      
461                 case ICMD_LADDCONST:            /* ..., value  ==> ..., value + constant        */
462                 case ICMD_LSUBCONST:            /* ..., value  ==> ..., value - constant        */
463                 case ICMD_IMULCONST:            /* ..., value  ==> ..., value * constant        */
464                 case ICMD_LMULCONST:            /* ..., value  ==> ..., value * constant        */
465                 case ICMD_IDIVPOW2:                     /* ..., value  ==> ..., value << constant       */
466                 case ICMD_LDIVPOW2:                     /* val.i = constant                                                     */
467                 case ICMD_ISHLCONST:            /* ..., value  ==> ..., value << constant       */
468                 case ICMD_ISHRCONST:            /* ..., value  ==> ..., value >> constant       */
469                 case ICMD_IUSHRCONST:           /* ..., value  ==> ..., value >>> constant      */
470                 case ICMD_LSHLCONST:            /* ..., value  ==> ..., value << constant       */
471                 case ICMD_LSHRCONST:            /* ..., value  ==> ..., value >> constant       */
472                 case ICMD_LUSHRCONST:           /* ..., value  ==> ..., value >>> constant      */
473                 case ICMD_IANDCONST:            /* ..., value  ==> ..., value & constant        */
474                 case ICMD_IREMPOW2:                     /* ..., value  ==> ..., value % constant        */
475                 case ICMD_LANDCONST:            /* ..., value  ==> ..., value & constant        */
476                 case ICMD_LREMPOW2:                     /* ..., value  ==> ..., value % constant        */
477                 case ICMD_IORCONST:                     /* ..., value  ==> ..., value | constant        */
478                 case ICMD_LORCONST:                     /* ..., value  ==> ..., value | constant        */  
479                 case ICMD_IXORCONST:            /* ..., value  ==> ..., value ^ constant        */
480                 case ICMD_LXORCONST:            /* ..., value  ==> ..., value ^ constant        */
481                 case ICMD_LCMP:                         /* ..., val1, val2  ==> ..., val1 cmp val2      */
482                         if (temp > 0)
483                                 return tracing(block, index-1, temp);
484                         else
485                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
486                         break;
487
488                 case ICMD_IINC:                         /* ..., value  ==> ..., value + constant        */
489                         return tracing(block, index-1, temp);
490                         break;
491
492
493                 /* floating operations                                                                                                  */
494                 case ICMD_FADD:                         /* ..., val1, val2  ==> ..., val1 + val2        */
495                 case ICMD_DADD:                         /* ..., val1, val2  ==> ..., val1 + val2        */
496                 case ICMD_FSUB:                         /* ..., val1, val2  ==> ..., val1 - val2        */
497                 case ICMD_DSUB:                         /* ..., val1, val2  ==> ..., val1 - val2        */
498                 case ICMD_FMUL:                         /* ..., val1, val2  ==> ..., val1 * val2        */
499                 case ICMD_DMUL:                         /* ..., val1, val2  ==> ..., val1 *** val2      */
500                 case ICMD_FDIV:                         /* ..., val1, val2  ==> ..., val1 / val2        */
501                 case ICMD_DDIV:                         /* ..., val1, val2  ==> ..., val1 / val2        */
502                 case ICMD_FREM:                         /* ..., val1, val2  ==> ..., val1 % val2        */
503                 case ICMD_DREM:                         /* ..., val1, val2  ==> ..., val1 % val2        */
504                 case ICMD_FCMPL:                        /* .., val1, val2  ==> ..., val1 fcmpl val2     */
505                 case ICMD_DCMPL:
506                 case ICMD_FCMPG:                        /* .., val1, val2  ==> ..., val1 fcmpg val2     */
507                 case ICMD_DCMPG:
508                         if (temp > 0)
509                                 return tracing(block, index-1, temp+1);
510                         else
511                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
512                         break;
513
514                 case ICMD_FNEG:                         /* ..., value  ==> ..., - value                         */
515                 case ICMD_DNEG:                         /* ..., value  ==> ..., - value                         */  
516                 case ICMD_I2F:                          /* ..., value  ==> ..., (float) value           */
517                 case ICMD_L2F:
518                 case ICMD_I2D:                          /* ..., value  ==> ..., (double) value          */
519                 case ICMD_L2D:
520                 case ICMD_F2I:                          /* ..., value  ==> ..., (int) value                     */
521                 case ICMD_D2I:
522                 case ICMD_F2L:                          /* ..., value  ==> ..., (long) value            */
523                 case ICMD_D2L:  
524                 case ICMD_F2D:                          /* ..., value  ==> ..., (double) value          */
525                 case ICMD_D2F:                          /* ..., value  ==> ..., (double) value          */
526                         if (temp > 0)
527                                 return tracing(block, index-1, temp);
528                         else
529                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
530                         break;
531    
532                 /* memory operations                                                                                                    */
533                  case ICMD_ARRAYLENGTH:         /* ..., arrayref  ==> ..., length                       */
534                         if (temp > 0)
535                                 return tracing(block, index-1, temp);
536                         else
537                                 return array_length(tracing(block, index-1, 0));
538                         break;
539
540                 case ICMD_AALOAD:                       /* ..., arrayref, index  ==> ..., value         */
541                 case ICMD_LALOAD:                       /* ..., arrayref, index  ==> ..., value         */  
542                 case ICMD_IALOAD:                       /* ..., arrayref, index  ==> ..., value         */
543                 case ICMD_FALOAD:                       /* ..., arrayref, index  ==> ..., value         */
544                 case ICMD_DALOAD:                       /* ..., arrayref, index  ==> ..., value         */
545                 case ICMD_CALOAD:                       /* ..., arrayref, index  ==> ..., value         */
546                 case ICMD_SALOAD:                       /* ..., arrayref, index  ==> ..., value         */
547                 case ICMD_BALOAD:                       /* ..., arrayref, index  ==> ..., value         */
548                         if (temp > 0)           
549                                 return tracing(block, index-1, temp+1);
550                         else
551                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
552                         break;
553
554                 case ICMD_AASTORE:                      /* ..., arrayref, index, value  ==> ...         */
555                 case ICMD_LASTORE:                      /* ..., arrayref, index, value  ==> ...         */
556                 case ICMD_IASTORE:                      /* ..., arrayref, index, value  ==> ...         */
557                 case ICMD_FASTORE:                      /* ..., arrayref, index, value  ==> ...         */
558                 case ICMD_DASTORE:                      /* ..., arrayref, index, value  ==> ...         */
559                 case ICMD_CASTORE:                      /* ..., arrayref, index, value  ==> ...         */
560                 case ICMD_SASTORE:                      /* ..., arrayref, index, value  ==> ...         */
561                 case ICMD_BASTORE:                      /* ..., arrayref, index, value  ==> ...         */
562                         return tracing(block, index-1, temp+3);
563                         break;
564  
565                 case ICMD_PUTSTATIC:        /* ..., value  ==> ...                    */
566                 case ICMD_PUTFIELD:         /* ..., value  ==> ...                    */
567                         return tracing(block, index - 1, temp + 1);
568                         break;
569  
570                 case ICMD_GETSTATIC:        /* ...  ==> ..., value                    */
571                 case ICMD_GETFIELD:         /* ...  ==> ..., value                    */
572                         if (temp > 0)
573                                 return tracing(block, index-1, temp - 1);
574                         else
575                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
576                         break;
577
578
579                 /* branch: should not be encountered, but function calls possible     */
580
581                 case ICMD_INVOKESTATIC:     /* ..., [arg1, [arg2 ...]] ==> ...        */
582                 case ICMD_INVOKESPECIAL:    /* ..., objectref, [arg1, [arg2 ...]] ==> . */
583                 case ICMD_INVOKEVIRTUAL:
584                 case ICMD_INVOKEINTERFACE:
585                         m = iptr->val.a;        /* get method pointer and                 */
586
587                         if (m)
588                                 md = m->parseddesc;
589                         else {
590                                 um = iptr->target;
591                                 md = um->methodref->parseddesc.md;
592                         }
593
594                         args = md->paramcount;  /* number of arguments                    */
595
596                         if (md->returntype.type != TYPE_VOID)
597                                 retval = 1;         /* if function returns a value, it is on  */
598                         else                    /* top of stack                           */
599                                 retval = 0;
600       
601                         if (temp > 0)           /* temp is increased by number of         */
602                                                 /* arguments a possible result value      */
603                                 return tracing(block, index - 1, temp + (args - retval));
604                         else
605                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
606                         break;
607
608
609                 /* special                                                            */
610
611                 case ICMD_INSTANCEOF:       /* ..., objectref ==> ..., intresult      */
612                 case ICMD_CHECKCAST:        /* ..., objectref ==> ..., objectref      */
613                         if (temp > 0)
614                                 return tracing(block, index-1, temp);
615                         else
616                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
617                         break;
618       
619                 case ICMD_MULTIANEWARRAY:       /* ..., cnt1, [cnt2, ...] ==> ..., arrayref     */
620                                                                         /* op1 = dimension                        */
621
622                         if (temp > 0)           /* temp increased by number of dimensions */
623                                                                         /* minus one for array ref                */
624                                 return tracing(block, index - 1, temp + (iptr->op1 - 1));
625                         else
626                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
627                         break;
628        
629                 case ICMD_BUILTIN:         /* ..., [arg1, [arg2 ...]] ==> ...         */
630                         bte = iptr->val.a;
631                         md = bte->md;
632                         args = md->paramcount;
633                         if (md->returntype.type != TYPE_VOID)
634                                 retval = 1;
635                         else
636                                 retval = 0;
637       
638                         if (temp > 0)           /* temp is increased by number of         */
639                                                 /* arguments less a possible result value */
640                                 return tracing(block, index - 1, temp + (args - retval));
641                         else
642                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
643                         break;
644
645
646                 /* others                                                             */
647
648                 default:
649                         return create_trace(TRACE_UNKNOWN, -1, 0, index);
650                         }       /* switch       */
651                 }               /* if           */
652
653         else
654                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
655 }
656
657
658 /*
659  * These are local overrides for various environment variables in Emacs.
660  * Please do not remove this and leave it at the end of the file, where
661  * Emacs will automagically detect them.
662  * ---------------------------------------------------------------------
663  * Local variables:
664  * mode: c
665  * indent-tabs-mode: t
666  * c-basic-offset: 4
667  * tab-width: 4
668  * End:
669  */