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