* Removed all Id tags.
[cacao.git] / src / vm / jit / loop / tracing.c
1 /* vm/jit/loop/tracing.c - trace functions
2
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
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., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
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 */
35
36
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"
42
43
44 /*      Test function -> will be removed in final release
45 */
46 void printTraceResult(struct Trace *p)
47 {
48         printf("TRACE: ");
49
50         switch (p->type) {
51         case TRACE_UNKNOWN:
52                 printf("\tUnknown");
53                 break;
54         case TRACE_ICONST:
55                 printf("\tconst - %d", p->constant);
56                 break;
57         case TRACE_ALENGTH:
58                 printf("\tarray - (%d)%d - %d", p->neg, p->var, p->constant);
59                 break;
60         case TRACE_IVAR:
61                 printf("\tivar - (%d)%d - %d", p->neg, p->var, p->constant);
62                 break;
63         case TRACE_AVAR:
64                 printf("\tavar - %d", p->var);
65                 break;
66                 }
67         
68         printf("\n");
69 }
70
71     
72 /*      A function that creates a new trace structure and initializes its values
73 */
74 Trace* create_trace(int type, int var, int constant, int nr)
75 {
76         Trace *t;
77
78         t = DNEW(Trace);
79
80         t->type = type;
81
82         t->neg = 1;
83         t->var = var;
84         t->nr = nr;
85
86         t->constant = constant;
87
88         return t;
89 }
90
91
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.
95 */
96 Trace* add(Trace* a, Trace* b)
97 {
98         switch (a->type) {                      /* check the first argument of add. when it             */
99         case TRACE_UNKNOWN:                     /* is unknown or array-address, return unknown  */
100         case TRACE_AVAR:
101                 return create_trace(TRACE_UNKNOWN, -1, 0, 0);
102
103         case TRACE_ICONST:                      /* when it is constant, check second argument   */
104                 switch (b->type) {
105                 case TRACE_IVAR:                        /* when second argument is a variable value */
106                 case TRACE_ALENGTH:                     /* or array length, just add the constant       */
107                         a->type = b->type;
108                         a->var  = b->var;
109                         a->neg  = b->neg;
110                         a->constant += b->constant;
111                         break;
112                 case TRACE_UNKNOWN:                     /* when unknown/array ref. return unknown       */
113                 case TRACE_AVAR:
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;
117                         break;
118                         }
119                 break;
120
121         case TRACE_IVAR:                        /* when it is a variable value or array length, */
122         case TRACE_ALENGTH:                     /* check second argument                                                */
123                 switch (b->type) {
124                 case TRACE_IVAR:                        /* when it is not a constant return unknown     */
125                 case TRACE_ALENGTH:
126                 case TRACE_UNKNOWN:
127                 case TRACE_AVAR:
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;
131                         break;
132                         }
133                 break;
134                 }
135
136         return a;
137 }
138
139
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.
143 */
144 Trace* negate(Trace* a)
145 {
146         switch (a->type) {                              /* check argument type                                          */
147         case TRACE_IVAR:                                /* when it is variable/array length value       */
148         case TRACE_ALENGTH:                                     
149                 a->neg = -(a->neg);                             /* invert negate flag                                   */
150                 a->constant = -(a->constant);   /* and negate constant                                  */
151                 break;
152         
153         case TRACE_ICONST:                              /* when it is a constant, negate it                     */
154                 a->constant = -(a->constant);
155                 break;
156
157         default:
158                 a->type = TRACE_UNKNOWN;        /* else return unknown                                          */
159                 break;
160                 }
161
162   return a;
163 }
164
165
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.
170 */
171 Trace* sub(Trace* a, Trace* b)
172 {
173         Trace *c = negate(b);
174         return add(a, c);
175 }
176
177
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 
181         this task.
182 */
183 Trace* array_length(Trace* a)
184 {
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      */
187         else
188                 a->type = TRACE_UNKNOWN;        /* else it's unknown                                    */
189
190         return a;
191 }
192
193
194 /* tracing *********************************************************************
195
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.
210
211 *******************************************************************************/
212
213 Trace* tracing(basicblock *block, int index, int temp)
214 {
215         instruction        *iptr;
216         methodinfo         *m;
217         builtintable_entry *bte;
218         methoddesc         *md;
219         s4                  args;
220         s4                  retval;
221
222         if (index >= 0) {
223                 iptr = block->iinstr + index;
224
225                 switch (iptr->opc) {
226                 
227                 /* nop, nullcheckpop                                                  */
228                 case ICMD_NOP:              /* ...  ==> ...                           */
229                         return tracing(block, index - 1, temp);
230                         break;
231       
232                 case ICMD_CHECKNULL:        /* ..., objectref  ==> ..., objectref     */
233                         return tracing(block, index-1, temp);
234                         break;
235
236                 /* Constants                                                          */
237                 case ICMD_LCONST:                               
238                 case ICMD_DCONST:
239                 case ICMD_FCONST:
240                 case ICMD_ACONST:
241                         if (temp > 0)                           
242                                 return tracing(block, index - 1, temp - 1);
243                         else
244                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
245                         break;                                          
246
247                 case ICMD_ICONST:
248                         if (temp > 0)           /* if the target argument is not on top                 */
249                                 return tracing(block, index-1, temp-1); /* look further                 */
250                         else
251                                 return create_trace(TRACE_ICONST, -1, iptr->val.i, index);
252                         break;                          /* else, return the value, found at this instr. */
253
254                 /* Load/Store                                                                                                                   */
255         case ICMD_LLOAD:                
256                 case ICMD_DLOAD:    
257                 case ICMD_FLOAD:
258                         if (temp > 0)
259                                 return tracing(block, index-1, temp-1);
260                         else
261                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
262                         break;
263     
264                 case ICMD_ILOAD:
265                         if (temp > 0)
266                                 return tracing(block, index-1, temp-1);
267                     else
268                                 return create_trace(TRACE_IVAR, iptr->op1, 0, index);
269                         break;
270
271                 case ICMD_ALOAD:    
272                         if (temp > 0)
273                                 return tracing(block, index-1, temp-1);
274                         else
275                                 return create_trace(TRACE_AVAR, iptr->op1, 0, index);                   
276                         break;
277                 
278                 case ICMD_LSTORE:    
279                 case ICMD_DSTORE:    
280                 case ICMD_FSTORE:
281                 case ICMD_ISTORE:
282                 case ICMD_ASTORE:    
283                         return tracing(block, index-1, temp+1);
284                         break;
285         
286
287                 /* pop/dup/swap                                                                                                                 */
288                 case ICMD_POP:      
289                         return tracing(block, index-1, temp+1);
290                         break;
291      
292                 case ICMD_POP2:  
293                         return tracing(block, index-1, temp+2);
294                         break;
295
296                 case ICMD_DUP:
297                         if (temp > 0)
298                                 return tracing(block, index-1, temp-1);
299                         else
300                                 return tracing(block, index-1, temp);
301                         break;
302
303                 case ICMD_DUP_X1:                       /* ..., a, b ==> ..., b, a, b                           */
304                         switch (temp) {
305                         case 0:                                 /* when looking for top or third element,       */
306                         case 2:                                 /* just return top element                                      */
307                                 return tracing(block, index-1, 0);
308                         case 1:
309                                 return tracing(block, index-1, 1);
310                         default:
311                                 return tracing(block, index-1, temp-1);
312                                 }
313                         break;
314
315                 case ICMD_DUP2:                         /* ..., a, b ==> ..., a, b, a, b                        */
316                         switch (temp) { 
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);
323                         default:
324                                 return tracing(block, index-1, temp-2);
325                                 }
326                         break;
327
328                 case ICMD_DUP2_X1:                      /* ..., a, b, c ==> ..., b, c, a, b, c          */
329                         switch (temp) {
330                         case 0:
331                         case 3:
332                                 return tracing(block, index-1, 0);
333                         case 1:
334                         case 4:
335                                 return tracing(block, index-1, 1);
336                         case 2:
337                                 return tracing(block, index-1, 2);
338                         default:
339                                 return tracing(block, index-1, temp-2);
340                                 }
341                         break;
342
343                 case ICMD_DUP_X2:                       /* ..., a, b, c ==> ..., c, a, b, c                     */
344                         switch (temp) {    
345                         case 0:
346                         case 3:
347                                 return tracing(block, index-1, 0);
348                         case 1:
349                         case 4:
350                                 return tracing(block, index-1, 1);
351                         case 2:
352                                 return tracing(block, index-1, 2);
353                         default:
354                                 return tracing(block, index-1, temp-2);
355                                 }
356                         break;
357
358                 case ICMD_DUP2_X2:                      /* .., a, b, c, d ==> ..., c, d, a, b, c, d     */
359                         switch (temp) {
360                         case 0:
361                         case 4:
362                                 return tracing(block, index-1, 0);
363                         case 1:
364                         case 5:
365                                 return tracing(block, index-1, 1);
366                         case 2:
367                                 return tracing(block, index-1, 2);
368                         case 3:
369                                 return tracing(block, index-1, 3);
370                         default:
371                                 return tracing(block, index-1, temp-2);
372                                 }
373                         break;
374
375                 case ICMD_SWAP:                         /* ..., a, b ==> ..., b, a                                      */
376                         switch (temp) {
377                         case 0:
378                                 return tracing(block, index-1, 1);
379                         case 1:
380                                 return tracing(block, index-1, 0);
381                         default:
382                                 return tracing(block, index-1, temp);
383                                 }
384                         break;
385       
386                 /* Interger operations                                                                                                  */
387             case ICMD_INEG:                             /* ..., value  ==> ..., - value                         */
388                         if (temp > 0)
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));
393                         break;
394
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                           */
401                         if (temp > 0)
402                                 return tracing(block, index-1, temp);
403                         else
404                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
405                         break;
406
407                 case ICMD_IADD:                         /* ..., val1, val2  ==> ..., val1 + val2        */
408                         if (temp > 0)
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));
412                         break;
413
414                 case ICMD_IADDCONST:            /* ..., value  ==> ..., value + constant        */
415                         if (temp > 0)
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));
420                         break;
421
422                 case ICMD_ISUB:                         /* ..., val1, val2  ==> ..., val1 - val2        */
423                         if (temp > 0)
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));
427                         break;
428
429                 case ICMD_ISUBCONST:            /* ..., value  ==> ..., value + constant        */
430                         if (temp > 0)
431                                 return tracing(block, index-1, temp);
432                         else
433                                 return sub(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, iptr->val.i, index));
434                         break;
435
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        */
447                 case ICMD_LAND:  
448                 case ICMD_IOR:                          /* ..., val1, val2  ==> ..., val1 | val2        */
449                 case ICMD_LOR:
450                 case ICMD_IXOR:                         /* ..., val1, val2  ==> ..., val1 ^ val2        */
451                 case ICMD_LXOR:
452                         if (temp > 0)
453                                 return tracing(block, index-1, temp+1);
454                         else
455                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
456                         break;
457      
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      */
479                         if (temp > 0)
480                                 return tracing(block, index-1, temp);
481                         else
482                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
483                         break;
484
485                 case ICMD_IINC:                         /* ..., value  ==> ..., value + constant        */
486                         return tracing(block, index-1, temp);
487                         break;
488
489
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     */
502                 case ICMD_DCMPL:
503                 case ICMD_FCMPG:                        /* .., val1, val2  ==> ..., val1 fcmpg val2     */
504                 case ICMD_DCMPG:
505                         if (temp > 0)
506                                 return tracing(block, index-1, temp+1);
507                         else
508                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
509                         break;
510
511                 case ICMD_FNEG:                         /* ..., value  ==> ..., - value                         */
512                 case ICMD_DNEG:                         /* ..., value  ==> ..., - value                         */  
513                 case ICMD_I2F:                          /* ..., value  ==> ..., (float) value           */
514                 case ICMD_L2F:
515                 case ICMD_I2D:                          /* ..., value  ==> ..., (double) value          */
516                 case ICMD_L2D:
517                 case ICMD_F2I:                          /* ..., value  ==> ..., (int) value                     */
518                 case ICMD_D2I:
519                 case ICMD_F2L:                          /* ..., value  ==> ..., (long) value            */
520                 case ICMD_D2L:  
521                 case ICMD_F2D:                          /* ..., value  ==> ..., (double) value          */
522                 case ICMD_D2F:                          /* ..., value  ==> ..., (double) value          */
523                         if (temp > 0)
524                                 return tracing(block, index-1, temp);
525                         else
526                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
527                         break;
528    
529                 /* memory operations                                                                                                    */
530                  case ICMD_ARRAYLENGTH:         /* ..., arrayref  ==> ..., length                       */
531                         if (temp > 0)
532                                 return tracing(block, index-1, temp);
533                         else
534                                 return array_length(tracing(block, index-1, 0));
535                         break;
536
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         */
545                         if (temp > 0)           
546                                 return tracing(block, index-1, temp+1);
547                         else
548                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
549                         break;
550
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);
560                         break;
561  
562                 case ICMD_PUTSTATIC:        /* ..., value  ==> ...                    */
563                 case ICMD_PUTFIELD:         /* ..., value  ==> ...                    */
564                         return tracing(block, index - 1, temp + 1);
565                         break;
566  
567                 case ICMD_GETSTATIC:        /* ...  ==> ..., value                    */
568                 case ICMD_GETFIELD:         /* ...  ==> ..., value                    */
569                         if (temp > 0)
570                                 return tracing(block, index-1, temp - 1);
571                         else
572                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
573                         break;
574
575
576                 /* branch: should not be encountered, but function calls possible     */
577
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);
583
584                         args = md->paramcount;  /* number of arguments                    */
585
586                         if (md->returntype.type != TYPE_VOID)
587                                 retval = 1;         /* if function returns a value, it is on  */
588                         else                    /* top of stack                           */
589                                 retval = 0;
590       
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));
594                         else
595                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
596                         break;
597
598
599                 /* special                                                            */
600
601                 case ICMD_INSTANCEOF:       /* ..., objectref ==> ..., intresult      */
602                 case ICMD_CHECKCAST:        /* ..., objectref ==> ..., objectref      */
603                         if (temp > 0)
604                                 return tracing(block, index-1, temp);
605                         else
606                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
607                         break;
608       
609                 case ICMD_MULTIANEWARRAY:       /* ..., cnt1, [cnt2, ...] ==> ..., arrayref     */
610                                                                         /* op1 = dimension                        */
611
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));
615                         else
616                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
617                         break;
618        
619                 case ICMD_BUILTIN:         /* ..., [arg1, [arg2 ...]] ==> ...         */
620                         bte = iptr->val.a;
621                         md = bte->md;
622                         args = md->paramcount;
623                         if (md->returntype.type != TYPE_VOID)
624                                 retval = 1;
625                         else
626                                 retval = 0;
627       
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));
631                         else
632                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
633                         break;
634
635
636                 /* others                                                             */
637
638                 default:
639                         return create_trace(TRACE_UNKNOWN, -1, 0, index);
640                         }       /* switch       */
641                 }               /* if           */
642
643         else
644                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
645 }
646
647
648 /*
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  * ---------------------------------------------------------------------
653  * Local variables:
654  * mode: c
655  * indent-tabs-mode: t
656  * c-basic-offset: 4
657  * tab-width: 4
658  * End:
659  */