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