changed descriptor2types to parsed descriptors and moved it to method.c
[cacao.git] / src / vm / jit / inline / inline.c
1 /* src/vm/jit/inline/inline.c - code inliner
2
3    Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Dieter Thuernbeck
28
29    $Id: inline.c 2184 2005-04-01 21:19:05Z edwin $
30
31 */
32
33 /*---
34 Inlining initializes an inline structure with values of the method called
35 with. Then it recursively to MAXDEPTH analyzes by parsing the bytecode 
36 looking for methods that meet the critera to be inlined.
37
38 Critera for inlining currently is:
39 Method to be inlined must:
40 - be less than MAXCODESIZE 
41 - only MAXMETHODS can be inlined in 1 method
42
43 -in only STATIC, FINAL, PRIVATE methods can be inlined from method's class
44 -ino (include outsiders) all STATIC, FINAL, PRIVATE methods can be inlined
45         note: PRIVATE is always only in the same class
46 -inv include virtual methods which static analysis (currently only RTA)
47      to only have 1 definition used (INVOKEVIRTUAL/INVOKEINTERFACE)
48      Currently dynamic loading is handled by rerunning with info 
49         (see parseRT). Guards need to be added.
50 -inp  inline parameters - Parameters are analysed if they are
51         readonly, which is used during parsing to generate ICMD_CLEAR_ARGREN
52         and ICMD_CLEAR_ARGREN is in turn used during stack analysis to
53         replace the ISTORE with a NOP so the same local variable is used.
54         Parameters are pushed on the stack, same as normal method 
55         invocation when popped the local variable of calling program is used.
56 -ine  JOWENN <- please add
57 ---*/
58
59 #include <stdio.h>
60 #include <string.h>
61
62 #include "mm/memory.h"
63 #include "toolbox/logging.h"
64 #include "vm/global.h"
65 #include "vm/linker.h"
66 #include "vm/loader.h"
67 #include "vm/tables.h"
68 #include "vm/options.h"
69 #include "vm/statistics.h"
70 #include "vm/jit/jit.h"
71 #include "vm/jit/parse.h"
72 #include "vm/jit/inline/inline.h"
73
74 #undef  INVIRTDEBUG  /* prints if a method was found to be 
75                          a unique virt/interface method  definition */
76 #undef DEBUGi 
77
78 #define METHINFOj(mm) \
79     { \
80         printf("<j%i/l%i/s%i/(p)%i>\t", \
81                 (mm)->jcodelength,(mm)->maxlocals, \
82                 (mm)->maxstack, (mm)->paramcount);  \
83         method_display_w_class(mm); }
84
85 #define METHINFOx(mm) \
86     { \
87         printf("<c%i/m%i/p%i>\t", \
88                 (mm)->class->classUsed,(mm)->methodUsed, (mm)->monoPoly); \
89         method_display_w_class(mm); }
90
91 #define METHINFO(m) \
92   method_display_w_class(m); 
93
94 #define IMETHINFO(m) \
95   utf_display(m->class->name); printf("."); fflush(stdout); \
96   method_display(m); fflush(stdout); \
97   printf("\tm->jcodelength=%i; ",m->jcodelength); fflush(stdout); \
98   printf("m->jcode=%p;\n",m->jcode); fflush(stdout); \
99   printf("\tm->maxlocals=%i; ",m->maxlocals); fflush(stdout); \
100   printf("m->maxstack=%i;\n",m->maxstack); fflush(stdout);
101
102 /* checked functions and macros: LOADCONST code_get OP1 BUILTIN block_insert bound_check ALIGN */
103
104 /* replace jcodelength loops with correct number after main for loop in parse()! */
105
106 #define CLASSINFO(cls) \
107         {       printf("<c%i>\t",cls->classUsed); \
108                 utf_display(cls->name); printf("\n");fflush(stdout);}
109
110 static bool in_stats1 = true;
111 /*-----------------------------------------------------------*/
112 /* just initialize global structure for non-inlining         */
113 /*-----------------------------------------------------------*/
114
115 void inlining_init0(methodinfo *m, t_inlining_globals *inline_env)
116 {
117         /* initialization for normal use in parse */
118         inlining_set_compiler_variables_fun(m, inline_env);
119         inline_env->isinlinedmethod = 0;
120         inline_env->cumjcodelength = m->jcodelength; /* for not inlining */
121
122         inline_env->cummaxstack = m->maxstack; 
123         inline_env->cumextablelength = 0;
124         inline_env->cumlocals = m->maxlocals;
125         inline_env->cummethods = 0; /* co not global or static-used only here? */
126         inline_env->inlining_stack = NULL;
127         inline_env->inlining_rootinfo = NULL;
128
129 #if defined(STATISTICS)
130         if (in_stats1) {
131                 int ii;
132                 for (ii=0; ii<512; ii++) count_in_not[ii]=0;
133                 in_stats1=false;
134                 }
135 #endif
136 }
137
138
139 /*-----------------------------------------------------------*/
140
141 void inlining_setup(methodinfo *m, t_inlining_globals *inline_env)
142 {
143
144 /*      t_inlining_globals *inline_env = DNEW(t_inlining_globals); */
145         inlining_init0(m,inline_env);
146
147 /* define in options.h; Used in main.c, jit.c & inline.c */
148 #ifdef INAFTERMAIN
149 if ((utf_new_char("main") == m->name) && (useinliningm)) {
150         useinlining = true;
151         }
152 #endif
153
154 if (useinlining)
155         {
156                 #ifdef DEBUGi
157                 printf("\n-------- Inlining init for: "); fflush(stdout);
158                 IMETHINFO(m)
159                 #endif
160                 
161         inline_env->cumjcodelength = 0;
162         inline_env->inlining_stack = NEW(list);
163         list_init(inline_env->inlining_stack, 
164                   OFFSET(t_inlining_stacknode, linkage));
165         /*------ analyze ------*/
166         inline_env->inlining_rootinfo 
167                 = inlining_analyse_method(m, 0, 0, 0, 0, inline_env);
168                 #ifdef DEBUGi
169                         printf ("\n------------------------------ ");fflush(stdout);
170                         printf ("\nComplete Result of inlining analysis of:");
171                         fflush(stdout);
172                         METHINFOj(m)
173                         print_t_inlining_globals(inline_env); /* init ok */
174                 #endif
175         /*---------------------*/
176 /*
177  if (inline_env->cummethods == 0) {
178          inline_env = DNEW(t_inlining_globals);
179          inlining_init0(m,inline_env);
180          return inline_env;
181  }
182 */
183 #if 0
184                 #ifdef DEBUGi
185   printf("(l,s) (%i,%i) was (%i,%i)\n",
186     m->maxlocals, inline_env->cumlocals,
187     m->maxstack,  inline_env->cummaxstack); fflush(stdout);
188                 #endif
189 /*This looks wrong*/
190 /* OK since other changes were also made, but in parse same stmt still */
191         m->maxlocals = inline_env->cumlocals;   orig not used
192         m->maxstack = inline_env->cummaxstack;  orig global maxstack var!!
193 #endif
194         }
195 }
196
197
198 void inlining_cleanup(t_inlining_globals *inline_env)
199 {
200         FREE(inline_env->inlining_stack, t_inlining_stacknode);
201 }
202
203
204 /*--2 push the compile variables to save the method's environment --*/
205
206 void inlining_push_compiler_variablesT(int opcode, inlining_methodinfo *inlinfo, t_inlining_globals *inline_env)
207 {
208         t_inlining_stacknode *new = NEW(t_inlining_stacknode);
209
210         /**new->opcode = opcode; **/
211         new->method = inline_env->method;
212         new->inlinfo = inlinfo;
213         list_addfirst(inline_env->inlining_stack, new);
214         inline_env->isinlinedmethod++;
215 }
216 /*-- push the compile variables to save the method's environment --*/
217
218 void inlining_push_compiler_variables(int i, int p, int nextp, int opcode,  u2 lineindex,u2 currentline,u2 linepcchange,inlining_methodinfo *inlinfo, t_inlining_globals *inline_env)
219 {
220         t_inlining_stacknode *new = NEW(t_inlining_stacknode);
221
222         new->i = i;
223         new->p = p;
224         new->nextp = nextp;
225         new->opcode = opcode;
226         new->method = inline_env->method;
227         new->lineindex=lineindex;
228         new->currentline=currentline;
229         new->linepcchange=linepcchange;
230         new->inlinfo = inlinfo;
231         list_addfirst(inline_env->inlining_stack, new);
232         inline_env->isinlinedmethod++;
233 }
234
235
236 void inlining_pop_compiler_variables(
237                                     int *i, int *p, int *nextp,
238                                     int *opcode, u2 *lineindex,
239                                     u2 *currentline,u2 *linepcchange,
240                                     inlining_methodinfo **inlinfo,
241                                     t_inlining_globals *inline_env)
242 {
243         t_inlining_stacknode *tmp 
244           = (t_inlining_stacknode *) list_first(inline_env->inlining_stack);
245
246         if (!inline_env->isinlinedmethod) panic("Attempting to pop from inlining stack in toplevel method!\n");
247
248         *i = tmp->i;
249         *p = tmp->p;
250         *nextp = tmp->nextp;
251         *opcode = tmp->opcode;
252
253         *lineindex=tmp->lineindex;
254         *currentline=tmp->currentline;
255         *currentline=tmp->linepcchange;
256
257         *inlinfo = tmp->inlinfo;
258
259         inline_env->method = tmp->method; /*co*/
260         inline_env->class = inline_env->method->class; /*co*/
261         inline_env->jcodelength = inline_env->method->jcodelength; /*co*/
262         inline_env->jcode = inline_env->method->jcode; /*co*/
263
264         list_remove(inline_env->inlining_stack, tmp);
265         FREE(tmp, t_inlining_stacknode);
266         inline_env->isinlinedmethod--;
267 }
268
269
270 void inlining_set_compiler_variables_fun(methodinfo *m,
271                                          t_inlining_globals *inline_env)
272 {
273         inline_env->method = m; 
274         inline_env->class  = m->class; 
275         inline_env->jcode  = m->jcode; 
276         inline_env->jcodelength = m->jcodelength; 
277 }
278
279 /* is_unique_method2 - determines if m is a unique method by looking
280         in subclasses of class that define method m 
281         It counts as it goes. It also saves the method name if found.
282
283  returns count of # methods used up to 2
284                                 (since if 2 used then not unique.)
285                        sets mout to method found 
286                                 (unique in class' heirarchy)
287                        It looks for subclasses with method def'd.
288  Input:
289  * class - where looking for method
290  * m     - original method ptr
291  * mout  - unique method (output) 
292  Output: "cnt" of methods found up to max of 2 (then not unique)
293 */
294
295 int is_unique_method2(classinfo *class, methodinfo *m, methodinfo **mout)
296 {
297 utf* name = m->name;
298 utf* desc = m->descriptor;
299
300 int cnt = 0;  /* number of times method found in USED classes in hierarchy*/
301 classinfo *subs1;          
302
303 if ((m->class == class) && (class->classUsed == USED)) {
304         /* found method in current class, which is used */
305         if (*mout != m) {
306                 cnt++;
307                 *mout = m;
308                 }
309         }
310
311 if ( ((m->flags & ACC_FINAL)  
312 ||    (class->sub == NULL))
313 && (class->classUsed == USED)) {
314         /* if final search no further */
315         if (*mout != m) {
316                 cnt++;
317                 *mout = m;
318                 }
319          return cnt;
320         }
321
322 /* search for the method in its subclasses */
323 for (subs1 = class->sub;subs1 != NULL;subs1 = subs1->nextsub) {
324         methodinfo * sm;
325         classinfo *subs = subs1;           
326         sm = class_resolveclassmethod(subs,name,desc,class,false);
327         if (sm != NULL) {
328                 if ((subs->classUsed == USED) && 
329                     (*mout != sm)) {
330                         *mout = sm;
331                         cnt++;
332                         }
333                 cnt = cnt + is_unique_method2(subs, sm, mout);
334                 /* Not unique if more than 1 def of method in class heir */
335                 if (cnt > 1)
336                         {return cnt;}
337                 }
338
339         }
340 return cnt;
341 }
342
343 /*-----------------------------------------------------------*/
344
345 bool is_unique_interface_method (methodinfo *mi, methodinfo **mout) {
346
347 utf* name = mi->name;
348 utf* desc = mi->descriptor;
349         
350         classSetNode *classImplNode;
351         int icnt = 0;
352
353         for (classImplNode  = mi->class->impldBy;
354              classImplNode != NULL;                     
355              classImplNode  = classImplNode->nextClass) {
356
357                 classinfo * classImplements = classImplNode->classType;
358                 methodinfo *submeth;
359
360                 submeth = class_findmethod(classImplements,name, desc); 
361                 if (submeth != NULL) {
362                         icnt =+ is_unique_method2(
363                                     classImplements,
364                                     submeth,
365                                     mout);
366                         }       
367                 if (icnt > 1) return false;
368                 } /* end for*/
369 if (icnt == 1) return true;
370 else return false;
371
372
373 /*-----------------------------------------------------------*/
374
375 bool can_inline (
376         t_inlining_globals *inline_env,
377         methodinfo *m,
378         methodinfo *imi,
379         constant_FMIref *imr,
380         bool uniqueVirt,
381         int opcode)
382         
383 /* options used inlinevirtual / uniqueVirt / inlineexctions  */
384 {
385 bool can = false;
386 u2 whycannot = 0;
387 if ((inline_env->cummethods < INLINING_MAXMETHODS) && 
388    /*** (!(imi->flags & ACC_ABSTRACT)) && /** Problem from INVOKE STATIC **/
389     (!(imi->flags & ACC_NATIVE)) &&
390     (inlineoutsiders || (m->class == imr->class)) &&
391     (imi->jcodelength < INLINING_MAXCODESIZE) &&
392     (imi->jcodelength > 0) &&        /* FIXME: eliminate empty methods? also abstract??*/
393     (((!inlinevirtuals)  ||
394       (uniqueVirt     ))   ||
395      ((opcode != JAVA_INVOKEVIRTUAL) ||
396       (opcode != JAVA_INVOKEINTERFACE)) ) &&
397     (inlineexceptions || (imi->exceptiontablelength == 0)))  {
398 #if defined(STATISTICS)
399         count_in++;
400         if (inlinevirtuals) { 
401                 if   (opcode == JAVA_INVOKEVIRTUAL) {
402                         if (uniqueVirt)  count_in_uniqVirt++; 
403                         }
404                 if   (opcode == JAVA_INVOKEINTERFACE) { 
405                         if (uniqueVirt)  count_in_uniqIntf++; 
406                         }
407                 }
408 #endif
409         can = true;
410         
411         }
412 else
413         can = false;
414 /*------ inline statistics ------*/
415 if ((!opt_stat) || can) return  can; 
416
417 if (!can) {
418   bool mult = false;
419
420 if  (imi->flags & ACC_NATIVE) return can; 
421 if  (imi->flags & ACC_ABSTRACT) return can; 
422 #if defined(STATISTICS)
423   count_in_rejected++;
424 #endif
425                                                 if (opt_verbose) 
426                                                         {char logtext[MAXLOGTEXT];
427                                                         sprintf(logtext, "Rejected to inline: ");
428                                                         utf_sprint(logtext  +strlen(logtext), imi->class->name);
429                                                         strcpy(logtext + strlen(logtext), ".");
430                                                         utf_sprint(logtext + strlen(logtext), imi->name);
431                                                         utf_sprint(logtext + strlen(logtext), imi->descriptor);
432                                                         log_text(logtext);
433                                                         METHINFOj(imi)
434                                                         }
435
436   if  (!(inlineoutsiders) && (m->class != imr->class)) {
437         /*** if ((!mult) && (whycannot > 0)) mult = true;  *** First time not needed ***/
438 #if defined(STATISTICS)
439         count_in_outsiders++;
440 #endif
441         whycannot = whycannot | IN_OUTSIDERS; /* outsider */ 
442         }
443   if (inline_env->cummethods >= INLINING_MAXMETHODS) { 
444         if ((!mult) && (whycannot > 0)) mult = true; 
445 #if defined(STATISTICS)
446         count_in_maxDepth++;
447 #endif
448         whycannot = whycannot | IN_MAXDEPTH;  
449         }
450   if  (imi->jcodelength >= INLINING_MAXCODESIZE) {
451         if ((!mult) && (whycannot > 0)) mult = true;
452         whycannot = whycannot | IN_MAXCODE;  
453         }
454   if  (imi->jcodelength > 0) {
455         if ((!mult) && (whycannot > 0)) mult = true;
456         whycannot = whycannot | IN_JCODELENGTH;  
457         }
458   if  (!inlineexceptions && (imi->exceptiontablelength == 0)) { 
459         whycannot = whycannot | IN_EXCEPTION;  
460         }
461   /* These must be last so mult flag is set correctly */ 
462   if  ( (inlinevirtuals) && 
463        ((opcode == JAVA_INVOKEVIRTUAL) ||
464         (opcode == JAVA_INVOKEINTERFACE)) ) { 
465         if (uniqueVirt )   { 
466                 /* so know why (and that) a unique virtual was rejected for another reason */ 
467                 if (opcode == JAVA_INVOKEVIRTUAL) { 
468 #if defined(STATISTICS)
469                         count_in_uniqueVirt_not_inlined++;
470 #endif
471                         whycannot = whycannot | IN_UNIQUEVIRT;  
472                         }
473                 else    {
474 #if defined(STATISTICS)
475                         count_in_uniqueInterface_not_inlined++;
476 #endif
477                         whycannot = whycannot | IN_UNIQUE_INTERFACE;  
478                         }
479                 }       
480         else    { /* not inlined because not not virtual */
481                 if ((!mult) && (whycannot > 0)) mult = true;
482                 if (opcode == JAVA_INVOKEVIRTUAL) { 
483                         whycannot = whycannot | IN_NOT_UNIQUE_VIRT;  
484                         }
485                 else    {
486                         whycannot = whycannot | IN_NOT_UNIQUE_INTERFACE;  
487                         }
488                 }       
489         }       
490
491   if  (inlineoutsiders && (m->class != imr->class)) {
492         whycannot = whycannot | IN_OUTSIDERS; /* outsider */ 
493 #if defined(STATISTICS)
494         count_in_outsiders++;
495 #endif
496         }
497
498 #if defined(STATISTICS)
499   if (mult)  
500         count_in_rejected_mult++;
501 #endif
502   if (whycannot > ((1<<IN_MAX)-1)) panic ("Inline Whynot is too large???\n");
503 #if defined(STATISTICS)
504   count_in_not[whycannot]++; 
505 #endif
506   }
507
508 return false;
509 }
510
511
512 /*-----------------------------------------------------------*/
513
514
515 inlining_methodinfo *inlining_analyse_method(methodinfo *m, 
516                                           int level, int gp, 
517                                           int firstlocal, int maxstackdepth,
518                                           t_inlining_globals *inline_env)
519 {
520         inlining_methodinfo *newnode = DNEW(inlining_methodinfo);
521         /*u1 *jcode = m->jcode;*/
522         int jcodelength = m->jcodelength;
523         int p;
524         int nextp;
525         int opcode;
526         int i=0;
527         bool iswide = false, oldiswide;
528         bool *readonly = NULL;
529         int  *label_index = NULL;
530         bool isnotrootlevel = (level > 0);
531         bool isnotleaflevel = (level < INLINING_MAXDEPTH);
532         bool maxdepthHit = false;
533         #ifdef DEBUGi
534                 printf ("\n------------------------------ ");fflush(stdout);
535                 printf ("\nStart of inlining analysis of: ");fflush(stdout);
536                 METHINFOj(m)
537                 if (isnotrootlevel) printf(" isnotrootlevel=T ");
538                 else printf(" isnotrootlevel=F ");
539                 print_t_inlining_globals(inline_env); /* init ok */
540         #endif
541         #undef DEBUGi
542
543         /* if (level == 0) gp = 0; */
544
545         if (isnotrootlevel) {
546                 newnode->readonly = readonly = DMNEW(bool, m->maxlocals); /* FIXME only paramcount entrys necessary - ok FIXED also turned on*/
547
548                 /** for (i = 0; i < m->maxlocals; readonly[i++] = true); **/
549                 for (i = 0; i < m->paramcount; readonly[i++] = true);
550                 /***isnotrootlevel = true; This had turned -inp off **/
551
552         } else {
553                 readonly = NULL;
554         }
555         
556         label_index = DMNEW(int, jcodelength+200);
557
558         newnode->inlinedmethods = DNEW(list);
559         list_init(newnode->inlinedmethods, OFFSET(inlining_methodinfo, linkage));
560
561         newnode->method = m;
562         newnode->level = level;
563         newnode->startgp = gp;
564         newnode->readonly = readonly;
565         newnode->label_index = label_index;
566         newnode->firstlocal = firstlocal;
567         inline_env->cumjcodelength += jcodelength + m->paramcount + 1 + 5;
568
569         if ((firstlocal + m->maxlocals) > inline_env->cumlocals) {
570                 inline_env->cumlocals = firstlocal + m->maxlocals;
571         }
572
573         if ((maxstackdepth + m->maxstack) > inline_env->cummaxstack) {
574                 inline_env->cummaxstack = maxstackdepth + m->maxstack;
575         }
576
577         inline_env->cumextablelength += m->exceptiontablelength;
578    
579
580         for (p = 0; p < jcodelength; gp += (nextp - p), p = nextp) {
581                 opcode = code_get_u1 (p,m);
582                 nextp = p + jcommandsize[opcode];
583                 oldiswide = iswide;
584
585                 /* figure out nextp */
586
587                 switch (opcode) {
588                 case JAVA_ILOAD:
589                 case JAVA_LLOAD:
590                 case JAVA_FLOAD:
591                 case JAVA_DLOAD:
592                 case JAVA_ALOAD: 
593
594                 case JAVA_ISTORE:
595                 case JAVA_LSTORE:
596                 case JAVA_FSTORE:
597                 case JAVA_DSTORE:
598                 case JAVA_ASTORE: 
599
600                 case JAVA_RET:
601                         if (iswide) {
602                                 nextp = p + 3;
603                                 iswide = false;
604                         }
605                         break;
606
607                 case JAVA_IINC:
608                         if (iswide) {
609                                 nextp = p + 5;
610                                 iswide = false;
611                         }
612                         break;
613
614                 case JAVA_WIDE:
615                         iswide = true;
616                         nextp = p + 1;
617                         break;
618
619                 case JAVA_LOOKUPSWITCH:
620                         nextp = ALIGN((p + 1), 4) + 4;
621                         nextp += code_get_u4(nextp,m) * 8 + 4;
622                         break;
623
624                 case JAVA_TABLESWITCH:
625                         nextp = ALIGN((p + 1), 4) + 4;
626                         nextp += (code_get_u4(nextp+4,m) - code_get_u4(nextp,m) + 1) * 4 + 4 +4;
627                         break;
628                 }
629
630                 /* detect readonly variables in inlined methods */
631                 
632                 if (isnotrootlevel) { 
633                         bool iswide = oldiswide;
634                         
635                         switch (opcode) {
636                         case JAVA_ISTORE:
637                         case JAVA_LSTORE:
638                         case JAVA_FSTORE:
639                         case JAVA_DSTORE:
640                         case JAVA_ASTORE: 
641                                 if (!iswide) {
642                                         i = code_get_u1(p + 1,m);
643
644                                 } else {
645                                         i = code_get_u2(p + 1,m);
646                                 }
647                                 readonly[i] = false;
648                                 break;
649
650                         case JAVA_ISTORE_0:
651                         case JAVA_LSTORE_0:
652                         case JAVA_FSTORE_0:
653                         case JAVA_ASTORE_0:
654                                 readonly[0] = false;
655                                 break;
656
657                         case JAVA_ISTORE_1:
658                         case JAVA_LSTORE_1:
659                         case JAVA_FSTORE_1:
660                         case JAVA_ASTORE_1:
661                                 readonly[1] = false;
662                                 break;
663
664                         case JAVA_ISTORE_2:
665                         case JAVA_LSTORE_2:
666                         case JAVA_FSTORE_2:
667                         case JAVA_ASTORE_2:
668                                 readonly[2] = false;
669                                 break;
670
671                         case JAVA_ISTORE_3:
672                         case JAVA_LSTORE_3:
673                         case JAVA_FSTORE_3:
674                         case JAVA_ASTORE_3:
675                                 readonly[3] = false;
676                                 break;
677
678                         case JAVA_IINC:
679                                 if (!iswide) {
680                                         i = code_get_u1(p + 1,m);
681
682                                 } else {
683                                         i = code_get_u2(p + 1,m);
684                                 }
685                                 readonly[i] = false;
686                                 break;
687                         }
688                 }
689
690                 /*              for (i=lastlabel; i<=p; i++) label_index[i] = gp; 
691                                 printf("lastlabel=%d p=%d gp=%d\n",lastlabel, p, gp);
692                 lastlabel = p+1; */
693                 for (i = p; i < nextp; i++) label_index[i] = gp;
694
695                 if (opt_stat) { 
696                         if ((!isnotrootlevel) && !maxdepthHit) {
697                                 maxdepthHit = true;
698 #if defined(STATISTICS)
699                                 count_in_maxDepth++;
700 #endif
701                         }
702                         }
703                 if (isnotleaflevel) { 
704
705                         switch (opcode) {
706
707                         case JAVA_INVOKEINTERFACE:
708                         case JAVA_INVOKEVIRTUAL:
709                                 if (!inlinevirtuals) 
710                                         break;
711                         
712                         case JAVA_INVOKESPECIAL:
713                         case JAVA_INVOKESTATIC:
714                                 i = code_get_u2(p + 1,m);
715                                 {
716                                         constant_FMIref *imr;
717                                         methodinfo *imi;
718
719                                         methodinfo *mout;
720                                         bool uniqueVirt= false;
721
722
723                                         if (opcode ==JAVA_INVOKEINTERFACE) {
724                                             imr = class_getconstant(m->class, i, CONSTANT_InterfaceMethodref);
725                                             LAZYLOADING(imr->class)
726                                             imi = class_resolveinterfacemethod(
727                                                 imr->class,
728                                                 imr->name,
729                                                 imr->descriptor,
730                                                 m->class,
731                                                 true);
732                                             if (!imi)  /* extra for debug */
733                                                 panic("ExceptionI thrown while parsing bytecode"); /* XXX should be passed on */
734                                            }
735                                         else {
736                                            imr = class_getconstant(m->class, i, CONSTANT_Methodref);
737                                            LAZYLOADING(imr->class)
738                                            imi = class_resolveclassmethod(
739                                                 imr->class,
740                                                 imr->name,
741                                                 imr->descriptor,
742                                                 m->class,
743                                                 true);
744                                             if (!imi) /* extra for debug */
745                                                 panic("Exception0 thrown while parsing bytecode"); /* XXX should be passed on */
746                                             }
747
748                                         if (!imi) /* normal-but never get here now */ 
749                                                 panic("Exception thrown while parsing bytecode"); /* XXX should be passed on */
750
751 /** Inlining has problem currently with typecheck & inlining **/
752 /** Due problem with typecheck & inlining, class checks fail for <init>s **/
753                                         if (utf_new_char("<init>") == imi->name) break; 
754                                         if (utf_new_char("finit$") == imi->name) break; 
755 /****/                                  
756                                         if (opcode == JAVA_INVOKEVIRTUAL) {
757                                                 mout = NULL;
758                                                 /* unique virt meth? then */
759                                                 /*  allow it to be inlined*/
760                                                 if (is_unique_method2(imi->class, imi, &mout) == 1) {
761                                                   if (mout != NULL) {
762                                                         imi = mout;
763                                                         uniqueVirt=true; 
764 #define INVIRTDEBUG
765 #ifdef INVIRTDEBUG
766                                                         METHINFOx(imi);
767                                                         printf("WAS unique virtual(-iv)\n");fflush(stdout);
768 #endif
769                                                         }
770                                                   } /* end is unique */
771                                                 } /* end INVOKEVIRTUAL */       
772                                         if (opcode == JAVA_INVOKEINTERFACE){
773                                                 mout = NULL; 
774 #ifdef INVIRTDEBUG
775                                                 METHINFOx(imi);
776 #endif
777                                                 if (is_unique_interface_method (imi,&mout)) {
778                                                      if (mout != NULL) {
779                                                         imi = mout;
780                                                         uniqueVirt=true;
781 #ifdef INVIRTDEBUG
782                                                           METHINFOx(imi);
783                                                           printf("WAS unique interface(-iv)\n");fflush(stdout);
784 #endif
785                                                         }
786                                                         
787                                                      } 
788                                                 } /* end INVOKEINTERFACE */     
789
790                                         if (can_inline(inline_env, m, imi, imr, uniqueVirt, opcode)) {
791                                                 inlining_methodinfo *tmp;
792                                                 method_descriptor2types(imi);
793
794                                                 inline_env->cummethods++;
795
796                                                 if (opt_verbose) 
797                                                         {char logtext[MAXLOGTEXT];
798                                                         printf("Going to inline: ");
799                                                         METHINFOj(imi) 
800                                                         printf("\nFrom "); fflush(stdout); METHINFOj(m)
801                                                         sprintf(logtext, "Going to inline: ");
802                                                         utf_sprint(logtext  +strlen(logtext), imi->class->name);
803                                                         strcpy(logtext + strlen(logtext), ".");
804                                                         utf_sprint(logtext + strlen(logtext), imi->name);
805                                                         utf_sprint(logtext + strlen(logtext), imi->descriptor);
806                                                         log_text(logtext);
807                                                         sprintf(logtext,"<%i>",imi->jcodelength);
808                                                         log_text(logtext);
809                                                         if ( (!(opcode == JAVA_INVOKEVIRTUAL)) &&
810                                                              (! ( (imi->flags & ACC_STATIC )
811                                                              ||   ((imi->flags & ACC_PRIVATE) && (imi->class == inline_env->class))
812                                                              ||   (imi->flags & ACC_FINAL  ))) )
813                                                            {
814                                                            printf("DEBUG WARNING:PROBABLE INLINE PROBLEM flags not static, private or final for non-virtual inlined method\n"); fflush(stdout);
815                                                            METHINFOx(imi);
816                                                            log_text("PROBABLE INLINE PROBLEM flags not static, private or final for non-virtual inlined method\n See method info after DEBUG WARNING\n");
817                                                            }
818
819                                                 }
820                                                 
821                                                 tmp =inlining_analyse_method(imi, level + 1, gp, firstlocal + m->maxlocals, maxstackdepth + m->maxstack, inline_env);
822                                                 list_addlast(newnode->inlinedmethods, tmp);
823                 #ifdef DEBUGi
824 printf("New node Right after an inline by:");fflush(stdout);
825 METHINFOj(m)
826 print_inlining_methodinfo(newnode);
827 printf("end new node\n"); fflush(stdout);
828                 #endif
829                                                 gp = tmp->stopgp;
830                                                 p = nextp;
831                                         }
832                                 }
833                                 break;
834                         }
835                 }  
836         } /* for */
837         
838         newnode->stopgp = gp;
839         label_index[jcodelength]=gp;
840     return newnode;
841 }
842
843 /* --------------------------------------------------------------------*/
844 /*  print_ functions: check inline structures contain what is expected */
845 /* --------------------------------------------------------------------*/
846 void print_t_inlining_globals (t_inlining_globals *g) 
847 {
848 printf("\n------------\nt_inlining_globals struct for: \n\t");fflush(stdout); 
849 METHINFOj(g->method);
850 printf("\tclass=");fflush(stdout);
851   utf_display(g->class->name);printf("\n");fflush(stdout);
852
853 printf("\tjcodelength=%i; jcode=%p;\n",g->jcodelength, g->jcode);
854
855 if (g->isinlinedmethod==true) {
856   printf("\tisinlinedmethod=true ");fflush(stdout);  
857   }
858 else {
859   printf("\tisinlinedmethod=false");fflush(stdout);  
860   }
861
862 printf("\tcumjcodelength=%i ,cummaxstack=%i ,cumextablelength=%i ",
863  g->cumjcodelength,    g->cummaxstack,  g->cumextablelength);fflush(stdout);
864 printf("\tcumlocals=%i ,cummethods=%i \n",
865  g->cumlocals,    g->cummethods);fflush(stdout);  
866
867 printf("s>s>s> ");fflush(stdout);
868         print_inlining_stack     (g->inlining_stack);
869 printf("i>i>i> "); fflush(stdout);
870         print_inlining_methodinfo(g->inlining_rootinfo);
871 printf("-------------------\n");fflush(stdout);
872 }
873
874 /* --------------------------------------------------------------------*/
875 void print_inlining_stack     ( list                *s)
876 {
877   t_inlining_stacknode *is;
878
879 if (s==NULL) { 
880   printf("\n\tinlining_stack: NULL\n");
881   return;
882   }
883
884 /* print first  element to see if get into stack */
885 printf("\n\tinlining_stack: NOT NULL\n");
886
887 is=list_first(s); 
888 if (is==NULL) { 
889     printf("\n\tinlining_stack = init'd but EMPTY\n");
890     fflush(stdout);
891     return;
892     }
893
894 printf("\n\tinlining_stack: NOT NULL\n");
895
896 for (is=list_first(s); 
897        is!=NULL;
898        is=list_next(s,is)) {
899          printf("\n\ti>--->inlining_stack entry: \n"); fflush(stdout);
900          METHINFOx(is->method);
901          printf("i=%i, p=%i, nextp=%i, opcode=%i;\n",
902                 is->i,is->p,is->nextp,is->opcode);fflush(stdout);
903          print_inlining_methodinfo(is->inlinfo);
904     } /*end for */
905 }
906
907 /* --------------------------------------------------------------------*/
908 void print_inlining_methodinfo( inlining_methodinfo *r) {
909   int i=0;
910   int cnt,cnt2;
911   inlining_methodinfo *im;
912   inlining_methodinfo *im2;
913   bool labellong = false;
914
915 if (r==NULL) { 
916   printf("\n\tinlining_methodinfo: NULL\n");
917   return;
918   }
919 printf("\n\tinlining_methodinfo for:"); fflush(stdout);
920
921 if (r->method != NULL) {
922   utf_display(r->method->class->name); printf("."); fflush(stdout); \
923   method_display(r->method); fflush(stdout); \
924   }
925 else {
926   printf(" NULL!!!!!\n");fflush(stdout);
927   }
928
929 if (r->readonly==NULL) {
930   printf("\treadonly==NULL ");fflush(stdout);  
931   }
932 else {
933   printf("\treadonly=");fflush(stdout);  
934   for (i = 0; i < r->method->maxlocals; i++)  {
935     if (r->readonly[i] == true)
936       printf("[i]=T;");
937     else
938       printf("[i]=F;");
939     fflush(stdout);
940     } 
941   }
942
943 /**printf("\tstartgp=%i; stopgp=%i; firstlocal=%i; label_index=%p;\n", **/
944 printf("\tstartgp=%i; stopgp=%i; firstlocal=%i; label_index=%p;\n",
945           r->startgp, r->stopgp, r->firstlocal, (void *)r->label_index);
946 printf ("label_index[0..%d]->", r->method->jcodelength);
947 if (labellong) {
948 for (i=0; i<r->method->jcodelength; i++) printf ("%d:%d ", i, r->label_index[i]); }
949 else {
950 printf ("%d:%d ", 0, r->label_index[i]);
951 printf ("%d:%d ", 
952   (r->method->jcodelength-1), r->label_index[r->method->jcodelength-1]);
953 }
954
955 printf("\n:::::inlines::::::::::::::::::::\n");
956 if (list_first(r->inlinedmethods) == NULL) {
957         printf("Nothing\n");fflush(stdout);
958         }
959 else {
960         for (im=list_first(r->inlinedmethods),cnt=0; 
961              im!=NULL;
962              im=list_next(r->inlinedmethods,im),cnt++) {
963                 printf("*"); fflush(stdout);
964                 printf("%i:",cnt);
965                 printf("[1L%i] ",im->firstlocal); fflush(stdout);
966                 METHINFOj(im->method)
967                 printf("::::: which inlines::"); fflush(stdout);        
968                 if (list_first(im->inlinedmethods) == NULL) {
969                         printf("Nothing\n");fflush(stdout);
970                         }
971                 else   {
972                         printf("##"); fflush(stdout);
973                         for (im2=list_first(im->inlinedmethods),cnt2=0; 
974                              im2!=NULL;
975                              im2=list_next(im2->inlinedmethods,im2),cnt2++) 
976                                 {
977                                 printf("\t%i::",cnt2); fflush(stdout);
978                                 printf("[1L%i] ",im2->firstlocal); 
979                                         fflush(stdout);
980                                 METHINFOj(im2->method)
981                                 }
982                         printf("\n"); fflush(stdout);
983                         }
984                 } 
985       }
986 }
987
988
989 /*
990  * These are local overrides for various environment variables in Emacs.
991  * Please do not remove this and leave it at the end of the file, where
992  * Emacs will automagically detect them.
993  * ---------------------------------------------------------------------
994  * Local variables:
995  * mode: c
996  * indent-tabs-mode: t
997  * c-basic-offset: 4
998  * tab-width: 4
999  * End:
1000  */