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