Major file restructuring.
[cacao.git] / src / vm / jit / loop / tracing.c
1 /* jit/loop/tracing.c - trace functions
2
3    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4    R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
5    M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
6    P. Tomsich, J. Wenninger
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 557 2003-11-02 22:51:59Z twisti $
35
36 */
37
38
39 #include <stdio.h>
40 #include "tracing.h"
41 #include "loop.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 struct Trace* create_trace(int type, int var, int constant, int nr)
75 {
76         struct Trace *t;
77         if ((t = (struct Trace *) malloc(sizeof(struct Trace))) == NULL)
78                 c_mem_error();
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 struct Trace* add(struct Trace* a, struct 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 struct Trace* negate(struct 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 struct Trace* sub(struct Trace* a, struct Trace* b)
172 {
173         struct 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 struct Trace* array_length(struct 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 /*      This function is used to identify the types of operands of an intermediate 
195         code instruction.It is needed by functions, that analyze array accesses. If 
196         something is stored into or loaded from an array, we have to find out, which 
197         array really has been accessed. When a compare instruction is encountered at
198         a loop header, the type of its operands have to be detected to construct
199         dynamic bounds for some variables in the loop. This function returns a struct
200         Trace (see loop.h for more details about this structure). block is the basic
201         block to be examined, index holds the offset of the examined instruction in
202         this block. The arguments are retrieved by using the stack structure, the 
203         compilation process sets up. During the backwards scan of the code, it is 
204         possible, that other instructions temporaray put or get values from the stack
205         and hide the value, we are interested in below them. The value temp counts
206         the number of values on the stack, the are located beyond the target value.
207 */
208 struct Trace* tracing(basicblock *block, int index, int temp)
209 {
210         int args, retval;
211         instruction *ip;
212         methodinfo *m;
213
214         if (index >= 0) {
215                 ip = block->iinstr+index;
216
217 /*      printf("TRACING with %d %d %d\n", index, temp, ip->opc);
218 */
219                 switch (ip->opc) {
220                 
221                 /* nop, nullcheckpop                                                                                                    */
222                 case ICMD_NOP:                          /* ...  ==> ...                                                         */
223                         return tracing(block, index-1, temp);
224                         break;
225       
226                 case ICMD_NULLCHECKPOP:         /* ..., objectref  ==> ...                                      */
227                         return tracing(block, index-1, temp+1);
228                         break;
229
230                 /* Constants                                                                                                                    */
231                 case ICMD_LCONST:                               
232                 case ICMD_DCONST:
233                 case ICMD_FCONST:
234                 case ICMD_ACONST:
235                         if (temp > 0)                           
236                                 return tracing(block, index-1, temp-1);         
237                         else
238                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
239                         break;                                          
240
241                 case ICMD_ICONST:
242                         if (temp > 0)           /* if the target argument is not on top                 */
243                                 return tracing(block, index-1, temp-1); /* look further                 */
244                         else
245                                 return create_trace(TRACE_ICONST, -1, ip->val.i, index);
246                         break;                          /* else, return the value, found at this instr. */
247
248                 /* Load/Store                                                                                                                   */
249         case ICMD_LLOAD:                
250                 case ICMD_DLOAD:    
251                 case ICMD_FLOAD:
252                         if (temp > 0)
253                                 return tracing(block, index-1, temp-1);
254                         else
255                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
256                         break;
257     
258                 case ICMD_ILOAD:
259                         if (temp > 0)
260                                 return tracing(block, index-1, temp-1);
261                     else
262                                 return create_trace(TRACE_IVAR, ip->op1, 0, index);
263                         break;
264
265                 case ICMD_ALOAD:    
266                         if (temp > 0)
267                                 return tracing(block, index-1, temp-1);
268                         else
269                                 return create_trace(TRACE_AVAR, ip->op1, 0, index);                     
270                         break;
271                 
272                 case ICMD_LSTORE:    
273                 case ICMD_DSTORE:    
274                 case ICMD_FSTORE:
275                 case ICMD_ISTORE:
276                 case ICMD_ASTORE:    
277                         return tracing(block, index-1, temp+1);
278                         break;
279         
280
281                 /* pop/dup/swap                                                                                                                 */
282                 case ICMD_POP:      
283                         return tracing(block, index-1, temp+1);
284                         break;
285      
286                 case ICMD_POP2:  
287                         return tracing(block, index-1, temp+2);
288                         break;
289
290                 case ICMD_DUP:
291                         if (temp > 0)
292                                 return tracing(block, index-1, temp-1);
293                         else
294                                 return tracing(block, index-1, temp);
295                         break;
296
297                 case ICMD_DUP_X1:                       /* ..., a, b ==> ..., b, a, b                           */
298                         switch (temp) {
299                         case 0:                                 /* when looking for top or third element,       */
300                         case 2:                                 /* just return top element                                      */
301                                 return tracing(block, index-1, 0);
302                         case 1:
303                                 return tracing(block, index-1, 1);
304                         default:
305                                 return tracing(block, index-1, temp-1);
306                                 }
307                         break;
308
309                 case ICMD_DUP2:                         /* ..., a, b ==> ..., a, b, a, b                        */
310                         switch (temp) { 
311                         case 0:                                 /* when looking for top or third element        */
312                         case 2:                                 /* just return top element                                      */
313                                 return tracing(block, index-1, 0);
314                         case 1:                                 /* when looking for second or fourth element*/
315                         case 3:                                 /* just return second element                           */
316                                 return tracing(block, index-1, 1);
317                         default:
318                                 return tracing(block, index-1, temp-2);
319                                 }
320                         break;
321
322                 case ICMD_DUP2_X1:                      /* ..., a, b, c ==> ..., b, c, a, b, c          */
323                         switch (temp) {
324                         case 0:
325                         case 3:
326                                 return tracing(block, index-1, 0);
327                         case 1:
328                         case 4:
329                                 return tracing(block, index-1, 1);
330                         case 2:
331                                 return tracing(block, index-1, 2);
332                         default:
333                                 return tracing(block, index-1, temp-2);
334                                 }
335                         break;
336
337                 case ICMD_DUP_X2:                       /* ..., a, b, c ==> ..., c, a, b, c                     */
338                         switch (temp) {    
339                         case 0:
340                         case 3:
341                                 return tracing(block, index-1, 0);
342                         case 1:
343                         case 4:
344                                 return tracing(block, index-1, 1);
345                         case 2:
346                                 return tracing(block, index-1, 2);
347                         default:
348                                 return tracing(block, index-1, temp-2);
349                                 }
350                         break;
351
352                 case ICMD_DUP2_X2:                      /* .., a, b, c, d ==> ..., c, d, a, b, c, d     */
353                         switch (temp) {
354                         case 0:
355                         case 4:
356                                 return tracing(block, index-1, 0);
357                         case 1:
358                         case 5:
359                                 return tracing(block, index-1, 1);
360                         case 2:
361                                 return tracing(block, index-1, 2);
362                         case 3:
363                                 return tracing(block, index-1, 3);
364                         default:
365                                 return tracing(block, index-1, temp-2);
366                                 }
367                         break;
368
369                 case ICMD_SWAP:                         /* ..., a, b ==> ..., b, a                                      */
370                         switch (temp) {
371                         case 0:
372                                 return tracing(block, index-1, 1);
373                         case 1:
374                                 return tracing(block, index-1, 0);
375                         default:
376                                 return tracing(block, index-1, temp);
377                                 }
378                         break;
379       
380                 /* Interger operations                                                                                                  */
381             case ICMD_INEG:                             /* ..., value  ==> ..., - value                         */
382                         if (temp > 0)
383                                 return tracing(block, index-1, temp);
384                         else                                    /* if an inter neg. operation is found,         */
385                                                                         /* invokethe negate function                            */
386                                 return negate(tracing(block, index-1, temp));
387                         break;
388
389                 case ICMD_LNEG:                         /* ..., value  ==> ..., - value                         */
390                 case ICMD_I2L:                          /* ..., value  ==> ..., value                           */
391                 case ICMD_L2I:                          /* ..., value  ==> ..., value                           */
392                 case ICMD_INT2BYTE:                     /* ..., value  ==> ..., value                           */
393                 case ICMD_INT2CHAR:                     /* ..., value  ==> ..., value                           */
394                 case ICMD_INT2SHORT:            /* ..., value  ==> ..., value                           */
395                         if (temp > 0)
396                                 return tracing(block, index-1, temp);
397                         else
398                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
399                         break;
400
401                 case ICMD_IADD:                         /* ..., val1, val2  ==> ..., val1 + val2        */
402                         if (temp > 0)
403                                 return tracing(block, index-1, temp+1);
404                         else                                    /* when add is encountered, invoke add func     */
405                                 return add(tracing(block, index-1, 0), tracing(block, index-1, 1));
406                         break;
407
408                 case ICMD_IADDCONST:            /* ..., value  ==> ..., value + constant        */
409                         if (temp > 0)
410                                 return tracing(block, index-1, temp);
411                         else                                    /* when a constant is added, create a           */
412                                                                         /* constant-trace and use add function          */
413                                 return add(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, ip->val.i, index));
414                         break;
415
416                 case ICMD_ISUB:                         /* ..., val1, val2  ==> ..., val1 - val2        */
417                         if (temp > 0)
418                                 return tracing(block, index-1, temp+1);
419                         else                                    /* use sub function for sub instructions        */
420                                 return sub(tracing(block, index-1, 1), tracing(block, index-1, 0));
421                         break;
422
423                 case ICMD_ISUBCONST:            /* ..., value  ==> ..., value + constant        */
424                         if (temp > 0)
425                                 return tracing(block, index-1, temp);
426                         else
427                                 return sub(tracing(block, index-1, 0), create_trace(TRACE_ICONST, -1, ip->val.i, index));
428                         break;
429
430                 case ICMD_LADD:                         /* ..., val1, val2  ==> ..., val1 + val2        */
431                 case ICMD_LSUB:                         /* ..., val1, val2  ==> ..., val1 - val2        */
432                 case ICMD_IMUL:                         /* ..., val1, val2  ==> ..., val1 * val2        */
433                 case ICMD_LMUL:                         /* ..., val1, val2  ==> ..., val1 * val2        */
434                 case ICMD_ISHL:                         /* ..., val1, val2  ==> ..., val1 << val2       */
435                 case ICMD_ISHR:                         /* ..., val1, val2  ==> ..., val1 >> val2       */
436                 case ICMD_IUSHR:                        /* ..., val1, val2  ==> ..., val1 >>> val2      */
437                 case ICMD_LSHL:                         /* ..., val1, val2  ==> ..., val1 << val2       */
438                 case ICMD_LSHR:                         /* ..., val1, val2  ==> ..., val1 >> val2       */
439                 case ICMD_LUSHR:                        /* ..., val1, val2  ==> ..., val1 >>> val2      */
440                 case ICMD_IAND:                         /* ..., val1, val2  ==> ..., val1 & val2        */
441                 case ICMD_LAND:  
442                 case ICMD_IOR:                          /* ..., val1, val2  ==> ..., val1 | val2        */
443                 case ICMD_LOR:
444                 case ICMD_IXOR:                         /* ..., val1, val2  ==> ..., val1 ^ val2        */
445                 case ICMD_LXOR:
446                         if (temp > 0)
447                                 return tracing(block, index-1, temp+1);
448                         else
449                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
450                         break;
451      
452                 case ICMD_LADDCONST:            /* ..., value  ==> ..., value + constant        */
453                 case ICMD_LSUBCONST:            /* ..., value  ==> ..., value - constant        */
454                 case ICMD_IMULCONST:            /* ..., value  ==> ..., value * constant        */
455                 case ICMD_LMULCONST:            /* ..., value  ==> ..., value * constant        */
456                 case ICMD_IDIVPOW2:                     /* ..., value  ==> ..., value << constant       */
457                 case ICMD_LDIVPOW2:                     /* val.i = constant                                                     */
458                 case ICMD_ISHLCONST:            /* ..., value  ==> ..., value << constant       */
459                 case ICMD_ISHRCONST:            /* ..., value  ==> ..., value >> constant       */
460                 case ICMD_IUSHRCONST:           /* ..., value  ==> ..., value >>> constant      */
461                 case ICMD_LSHLCONST:            /* ..., value  ==> ..., value << constant       */
462                 case ICMD_LSHRCONST:            /* ..., value  ==> ..., value >> constant       */
463                 case ICMD_LUSHRCONST:           /* ..., value  ==> ..., value >>> constant      */
464                 case ICMD_IANDCONST:            /* ..., value  ==> ..., value & constant        */
465                 case ICMD_IREMPOW2:                     /* ..., value  ==> ..., value % constant        */
466                 case ICMD_IREM0X10001:          /* ..., value  ==> ..., value % 0x100001        */
467                 case ICMD_LANDCONST:            /* ..., value  ==> ..., value & constant        */
468                 case ICMD_LREMPOW2:                     /* ..., value  ==> ..., value % constant        */
469                 case ICMD_LREM0X10001:          /* ..., value  ==> ..., value % 0x10001         */
470                 case ICMD_IORCONST:                     /* ..., value  ==> ..., value | constant        */
471                 case ICMD_LORCONST:                     /* ..., value  ==> ..., value | constant        */  
472                 case ICMD_IXORCONST:            /* ..., value  ==> ..., value ^ constant        */
473                 case ICMD_LXORCONST:            /* ..., value  ==> ..., value ^ constant        */
474                 case ICMD_LCMP:                         /* ..., val1, val2  ==> ..., val1 cmp val2      */
475                         if (temp > 0)
476                                 return tracing(block, index-1, temp);
477                         else
478                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
479                         break;
480
481                 case ICMD_IINC:                         /* ..., value  ==> ..., value + constant        */
482                         return tracing(block, index-1, temp);
483                         break;
484
485
486                 /* floating operations                                                                                                  */
487                 case ICMD_FADD:                         /* ..., val1, val2  ==> ..., val1 + val2        */
488                 case ICMD_DADD:                         /* ..., val1, val2  ==> ..., val1 + val2        */
489                 case ICMD_FSUB:                         /* ..., val1, val2  ==> ..., val1 - val2        */
490                 case ICMD_DSUB:                         /* ..., val1, val2  ==> ..., val1 - val2        */
491                 case ICMD_FMUL:                         /* ..., val1, val2  ==> ..., val1 * val2        */
492                 case ICMD_DMUL:                         /* ..., val1, val2  ==> ..., val1 *** val2      */
493                 case ICMD_FDIV:                         /* ..., val1, val2  ==> ..., val1 / val2        */
494                 case ICMD_DDIV:                         /* ..., val1, val2  ==> ..., val1 / val2        */
495                 case ICMD_FREM:                         /* ..., val1, val2  ==> ..., val1 % val2        */
496                 case ICMD_DREM:                         /* ..., val1, val2  ==> ..., val1 % val2        */
497                 case ICMD_FCMPL:                        /* .., val1, val2  ==> ..., val1 fcmpl val2     */
498                 case ICMD_DCMPL:
499                 case ICMD_FCMPG:                        /* .., val1, val2  ==> ..., val1 fcmpg val2     */
500                 case ICMD_DCMPG:
501                         if (temp > 0)
502                                 return tracing(block, index-1, temp+1);
503                         else
504                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
505                         break;
506
507                 case ICMD_FNEG:                         /* ..., value  ==> ..., - value                         */
508                 case ICMD_DNEG:                         /* ..., value  ==> ..., - value                         */  
509                 case ICMD_I2F:                          /* ..., value  ==> ..., (float) value           */
510                 case ICMD_L2F:
511                 case ICMD_I2D:                          /* ..., value  ==> ..., (double) value          */
512                 case ICMD_L2D:
513                 case ICMD_F2I:                          /* ..., value  ==> ..., (int) value                     */
514                 case ICMD_D2I:
515                 case ICMD_F2L:                          /* ..., value  ==> ..., (long) value            */
516                 case ICMD_D2L:  
517                 case ICMD_F2D:                          /* ..., value  ==> ..., (double) value          */
518                 case ICMD_D2F:                          /* ..., value  ==> ..., (double) value          */
519                         if (temp > 0)
520                                 return tracing(block, index-1, temp);
521                         else
522                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
523                         break;
524    
525                 /* memory operations                                                                                                    */
526                  case ICMD_ARRAYLENGTH:         /* ..., arrayref  ==> ..., length                       */
527                         if (temp > 0)
528                                 return tracing(block, index-1, temp);
529                         else
530                                 return array_length(tracing(block, index-1, 0));
531                         break;
532
533                 case ICMD_AALOAD:                       /* ..., arrayref, index  ==> ..., value         */
534                 case ICMD_LALOAD:                       /* ..., arrayref, index  ==> ..., value         */  
535                 case ICMD_IALOAD:                       /* ..., arrayref, index  ==> ..., value         */
536                 case ICMD_FALOAD:                       /* ..., arrayref, index  ==> ..., value         */
537                 case ICMD_DALOAD:                       /* ..., arrayref, index  ==> ..., value         */
538                 case ICMD_CALOAD:                       /* ..., arrayref, index  ==> ..., value         */
539                 case ICMD_SALOAD:                       /* ..., arrayref, index  ==> ..., value         */
540                 case ICMD_BALOAD:                       /* ..., arrayref, index  ==> ..., value         */
541                         if (temp > 0)           
542                                 return tracing(block, index-1, temp+1);
543                         else
544                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
545                         break;
546
547                 case ICMD_AASTORE:                      /* ..., arrayref, index, value  ==> ...         */
548                 case ICMD_LASTORE:                      /* ..., arrayref, index, value  ==> ...         */
549                 case ICMD_IASTORE:                      /* ..., arrayref, index, value  ==> ...         */
550                 case ICMD_FASTORE:                      /* ..., arrayref, index, value  ==> ...         */
551                 case ICMD_DASTORE:                      /* ..., arrayref, index, value  ==> ...         */
552                 case ICMD_CASTORE:                      /* ..., arrayref, index, value  ==> ...         */
553                 case ICMD_SASTORE:                      /* ..., arrayref, index, value  ==> ...         */
554                 case ICMD_BASTORE:                      /* ..., arrayref, index, value  ==> ...         */
555                         return tracing(block, index-1, temp+3);
556                         break;
557  
558                 case ICMD_PUTSTATIC:            /* ..., value  ==> ...                                          */
559                 case ICMD_PUTFIELD:                     /* ..., value  ==> ...                                          */
560                         return tracing(block, index-1, temp+1);
561                         break;
562  
563                 case ICMD_GETSTATIC:            /* ...  ==> ..., value                                          */
564                 case ICMD_GETFIELD:                     /* ...  ==> ..., value                                          */
565                         if (temp > 0)
566                                 return tracing(block, index-1, temp-1);
567                         else
568                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
569                         break;
570
571
572                 /* branch: should not be encountered, but function calls possible               */
573                 case ICMD_INVOKESTATIC:         /* ..., [arg1, [arg2 ...]] ==> ...                      */
574                         m = ip->val.a;                  /* get method pointer and                                       */
575                         args = ip->op1;                 /* number of arguments                                          */
576                         if (m->returntype != TYPE_VOID)
577                                 retval = 1;                     /* if function returns a value, it is on        */
578                         else                                    /* top of stack                                                         */
579                                 retval = 0;
580       
581                         if (temp > 0)                   /* temp is increased by number of arguments     */
582                                                                         /* less a possible result value                         */
583                                 return tracing(block, index-1, temp+(args-retval));
584                         else
585                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
586                         break;
587
588                 case ICMD_INVOKESPECIAL:        /* ..., objectref, [arg1, [arg2 ...]] ==> .     */
589                 case ICMD_INVOKEVIRTUAL:        /* ..., objectref, [arg1, [arg2 ...]] ==> .     */
590                 case ICMD_INVOKEINTERFACE:      /* ..., objectref, [arg1, [arg2 ...]] ==> . */
591                         m = ip->val.a;
592                         args = ip->op1; 
593                         if (m->returntype != TYPE_VOID)
594                                 retval = 1;
595                         else
596                                 retval = 0;
597                         
598                         if (temp > 0)                   /* same as above but add 1 for object ref       */
599                                 return tracing(block, index-1, temp+(args-retval+1));
600                         else
601                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
602                         break;
603  
604                 /* special                                                                                                                              */  
605                 case ICMD_INSTANCEOF:           /* ..., objectref ==> ..., intresult            */
606                 case ICMD_CHECKCAST:            /* ..., objectref ==> ..., objectref            */
607                         if (temp > 0)
608                                 return tracing(block, index-1, temp);
609                         else
610                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
611                         break;
612       
613                 case ICMD_MULTIANEWARRAY:       /* ..., cnt1, [cnt2, ...] ==> ..., arrayref     */
614                                                                         /* op1 = dimension                                                      */ 
615
616                         if (temp > 0)                   /* temp increased by number of dimensions       */
617                                                                         /* minus one for array ref                                      */
618                                 return tracing(block, index-1, temp+(ip->op1 - 1));
619                         else
620                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
621                         break;
622        
623                 case ICMD_BUILTIN3:                     /* ..., arg1, arg2, arg3 ==> ...                        */
624                         if (ip->op1 != TYPE_VOID)
625                                 retval = 1;
626                         else
627                                 retval = 0;
628       
629                         if (temp > 0)                   /* increase temp by 3 minus possible return     */
630                                                                         /* value                                                                        */
631                                 return tracing(block, index-1, temp+(3-retval));
632                         else
633                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
634                         break;
635
636                 case ICMD_BUILTIN2:                     /* ..., arg1, arg2 ==> ...                                      */
637                         if (ip->op1 != TYPE_VOID)
638                                 retval = 1;
639                         else
640                                 retval = 0;
641                         if (temp > 0)
642                                 return tracing(block, index-1, temp+(2-retval));
643                         else
644                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
645                         break;
646
647                 case ICMD_BUILTIN1:     /* ..., arg1 ==> ...                                                    */
648                         if (ip->op1 != TYPE_VOID)
649                                 retval = 1;
650                         else
651                                 retval = 0;
652                         if (temp > 0)
653                                 return tracing(block, index-1, temp+(1-retval));
654                         else
655                                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
656                         break;
657
658                 /* others                                                                                                                               */
659                 default:
660                         return create_trace(TRACE_UNKNOWN, -1, 0, index);
661                         }       /* switch       */
662                 }               /* if           */
663         else
664                 return create_trace(TRACE_UNKNOWN, -1, 0, index);
665 }
666
667
668 /*
669  * These are local overrides for various environment variables in Emacs.
670  * Please do not remove this and leave it at the end of the file, where
671  * Emacs will automagically detect them.
672  * ---------------------------------------------------------------------
673  * Local variables:
674  * mode: c
675  * indent-tabs-mode: t
676  * c-basic-offset: 4
677  * tab-width: 4
678  * End:
679  */