* Updated header: Added 2006. Changed address of FSF. Changed email
[cacao.git] / src / vm / jit / inline / inline.c
1 /* src/vm/jit/inline/inline.c - code inliner
2
3    Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, 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., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Dieter Thuernbeck
28
29    Changes: Christian Thalinger
30
31    $Id: inline.c 4357 2006-01-22 23:33:38Z 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_println(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_println(mm); }
94
95 #define METHINFO(m) \
96   method_println(m); 
97
98 #define IMETHINFO(m) \
99   utf_display(m->class->name); printf("."); fflush(stdout); \
100   method_println(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 if (useinlining)
152         {
153                 #ifdef DEBUGi
154                 printf("\n-------- Inlining init for: "); fflush(stdout);
155                 IMETHINFO(m)
156                 #endif
157                 
158         inline_env->cumjcodelength = 0;
159         inline_env->inlining_stack = NEW(list);
160         list_init(inline_env->inlining_stack, 
161                   OFFSET(t_inlining_stacknode, linkage));
162         /*------ analyze ------*/
163         inline_env->inlining_rootinfo 
164                 = inlining_analyse_method(m, 0, 0, 0, 0, inline_env);
165                 #ifdef DEBUGi
166                         printf ("\n------------------------------ ");fflush(stdout);
167                         printf ("\nComplete Result of inlining analysis of:");
168                         fflush(stdout);
169                         METHINFOj(m)
170                         print_t_inlining_globals(inline_env); /* init ok */
171                 #endif
172         /*---------------------*/
173 /*
174  if (inline_env->cummethods == 0) {
175          inline_env = DNEW(t_inlining_globals);
176          inlining_init0(m,inline_env);
177          return inline_env;
178  }
179 */
180 #if 0
181                 #ifdef DEBUGi
182   printf("(l,s) (%i,%i) was (%i,%i)\n",
183     m->maxlocals, inline_env->cumlocals,
184     m->maxstack,  inline_env->cummaxstack); fflush(stdout);
185                 #endif
186 /*This looks wrong*/
187 /* OK since other changes were also made, but in parse same stmt still */
188         m->maxlocals = inline_env->cumlocals;   orig not used
189         m->maxstack = inline_env->cummaxstack;  orig global maxstack var!!
190 #endif
191         }
192 }
193
194
195 void inlining_cleanup(t_inlining_globals *inline_env)
196 {
197         FREE(inline_env->inlining_stack, t_inlining_stacknode);
198 }
199
200
201 /*--2 push the compile variables to save the method's environment --*/
202
203 void inlining_push_compiler_variablesT(int opcode, inlining_methodinfo *inlinfo, t_inlining_globals *inline_env)
204 {
205         t_inlining_stacknode *new = NEW(t_inlining_stacknode);
206
207         /**new->opcode = opcode; **/
208         new->method = inline_env->method;
209         new->inlinfo = inlinfo;
210         list_addfirst(inline_env->inlining_stack, new);
211         inline_env->isinlinedmethod++;
212 }
213 /*-- push the compile variables to save the method's environment --*/
214
215 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)
216 {
217         t_inlining_stacknode *new = NEW(t_inlining_stacknode);
218
219         new->i = i;
220         new->p = p;
221         new->nextp = nextp;
222         new->opcode = opcode;
223         new->method = inline_env->method;
224         new->lineindex=lineindex;
225         new->currentline=currentline;
226         new->linepcchange=linepcchange;
227         new->inlinfo = inlinfo;
228         list_addfirst(inline_env->inlining_stack, new);
229         inline_env->isinlinedmethod++;
230 }
231
232
233 void inlining_pop_compiler_variables(
234                                     int *i, int *p, int *nextp,
235                                     int *opcode, u2 *lineindex,
236                                     u2 *currentline,u2 *linepcchange,
237                                     inlining_methodinfo **inlinfo,
238                                     t_inlining_globals *inline_env)
239 {
240         t_inlining_stacknode *tmp 
241           = (t_inlining_stacknode *) list_first(inline_env->inlining_stack);
242
243         if (!inline_env->isinlinedmethod) {
244                 log_text("Attempting to pop from inlining stack in toplevel method!");
245                 assert(0);
246         }
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->name == imr->classref->name)) &&
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(ENABLE_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(ENABLE_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->name != imr->classref->name)) {
437         /*** if ((!mult) && (whycannot > 0)) mult = true;  *** First time not needed ***/
438 #if defined(ENABLE_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(ENABLE_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(ENABLE_STATISTICS)
469                         count_in_uniqueVirt_not_inlined++;
470 #endif
471                         whycannot = whycannot | IN_UNIQUEVIRT;  
472                         }
473                 else    {
474 #if defined(ENABLE_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->name != imr->classref->name)) {
492         whycannot = whycannot | IN_OUTSIDERS; /* outsider */ 
493 #if defined(ENABLE_STATISTICS)
494         count_in_outsiders++;
495 #endif
496         }
497
498 #if defined(ENABLE_STATISTICS)
499   if (mult)  
500         count_in_rejected_mult++;
501 #endif
502   if (whycannot > ((1<<IN_MAX)-1)) {
503           log_text("Inline Whynot is too large???");
504           assert(0);
505   }
506 #if defined(ENABLE_STATISTICS)
507   count_in_not[whycannot]++; 
508 #endif
509   }
510
511 return false;
512 }
513
514
515 /*-----------------------------------------------------------*/
516
517
518 inlining_methodinfo *inlining_analyse_method(methodinfo *m, 
519                                           int level, int gp, 
520                                           int firstlocal, int maxstackdepth,
521                                           t_inlining_globals *inline_env)
522 {
523         inlining_methodinfo *newnode = DNEW(inlining_methodinfo);
524         /*u1 *jcode = m->jcode;*/
525         int jcodelength = m->jcodelength;
526         int p;
527         int nextp;
528         int opcode;
529         int i=0;
530         bool iswide = false, oldiswide;
531         bool *readonly = NULL;
532         int  *label_index = NULL;
533         bool isnotrootlevel = (level > 0);
534         bool isnotleaflevel = (level < INLINING_MAXDEPTH);
535         bool maxdepthHit = false;
536         #ifdef DEBUGi
537                 printf ("\n------------------------------ ");fflush(stdout);
538                 printf ("\nStart of inlining analysis of: ");fflush(stdout);
539                 METHINFOj(m)
540                 if (isnotrootlevel) printf(" isnotrootlevel=T ");
541                 else printf(" isnotrootlevel=F ");
542                 print_t_inlining_globals(inline_env); /* init ok */
543         #endif
544         #undef DEBUGi
545
546         /* if (level == 0) gp = 0; */
547
548         if (isnotrootlevel) {
549                 newnode->readonly = readonly = DMNEW(bool, m->maxlocals); /* FIXME only paramcount entrys necessary - ok FIXED also turned on*/
550
551                 /** for (i = 0; i < m->maxlocals; readonly[i++] = true); **/
552                 for (i = 0; i < m->paramcount; readonly[i++] = true);
553                 /***isnotrootlevel = true; This had turned -inp off **/
554
555         } else {
556                 readonly = NULL;
557         }
558         
559         label_index = DMNEW(int, jcodelength+200);
560
561         newnode->inlinedmethods = DNEW(list);
562         list_init(newnode->inlinedmethods, OFFSET(inlining_methodinfo, linkage));
563
564         newnode->method = m;
565         newnode->level = level;
566         newnode->startgp = gp;
567         newnode->readonly = readonly;
568         newnode->label_index = label_index;
569         newnode->firstlocal = firstlocal;
570         inline_env->cumjcodelength += jcodelength + m->paramcount + 1 + 5;
571
572         if ((firstlocal + m->maxlocals) > inline_env->cumlocals) {
573                 inline_env->cumlocals = firstlocal + m->maxlocals;
574         }
575
576         if ((maxstackdepth + m->maxstack) > inline_env->cummaxstack) {
577                 inline_env->cummaxstack = maxstackdepth + m->maxstack;
578         }
579
580         inline_env->cumextablelength += m->exceptiontablelength;
581    
582
583         for (p = 0; p < jcodelength; gp += (nextp - p), p = nextp) {
584                 opcode = code_get_u1 (p,m);
585                 nextp = p + jcommandsize[opcode];
586                 oldiswide = iswide;
587
588                 /* figure out nextp */
589
590                 switch (opcode) {
591                 case JAVA_ILOAD:
592                 case JAVA_LLOAD:
593                 case JAVA_FLOAD:
594                 case JAVA_DLOAD:
595                 case JAVA_ALOAD: 
596
597                 case JAVA_ISTORE:
598                 case JAVA_LSTORE:
599                 case JAVA_FSTORE:
600                 case JAVA_DSTORE:
601                 case JAVA_ASTORE: 
602
603                 case JAVA_RET:
604                         if (iswide) {
605                                 nextp = p + 3;
606                                 iswide = false;
607                         }
608                         break;
609
610                 case JAVA_IINC:
611                         if (iswide) {
612                                 nextp = p + 5;
613                                 iswide = false;
614                         }
615                         break;
616
617                 case JAVA_WIDE:
618                         iswide = true;
619                         nextp = p + 1;
620                         break;
621
622                 case JAVA_LOOKUPSWITCH:
623                         nextp = ALIGN((p + 1), 4) + 4;
624                         nextp += code_get_u4(nextp,m) * 8 + 4;
625                         break;
626
627                 case JAVA_TABLESWITCH:
628                         nextp = ALIGN((p + 1), 4) + 4;
629                         nextp += (code_get_u4(nextp+4,m) - code_get_u4(nextp,m) + 1) * 4 + 4 +4;
630                         break;
631                 }
632
633                 /* detect readonly variables in inlined methods */
634                 
635                 if (isnotrootlevel) { 
636                         bool iswide = oldiswide;
637                         
638                         switch (opcode) {
639                         case JAVA_ISTORE:
640                         case JAVA_LSTORE:
641                         case JAVA_FSTORE:
642                         case JAVA_DSTORE:
643                         case JAVA_ASTORE: 
644                                 if (!iswide) {
645                                         i = code_get_u1(p + 1,m);
646
647                                 } else {
648                                         i = code_get_u2(p + 1,m);
649                                 }
650                                 readonly[i] = false;
651                                 break;
652
653                         case JAVA_ISTORE_0:
654                         case JAVA_LSTORE_0:
655                         case JAVA_FSTORE_0:
656                         case JAVA_ASTORE_0:
657                                 readonly[0] = false;
658                                 break;
659
660                         case JAVA_ISTORE_1:
661                         case JAVA_LSTORE_1:
662                         case JAVA_FSTORE_1:
663                         case JAVA_ASTORE_1:
664                                 readonly[1] = false;
665                                 break;
666
667                         case JAVA_ISTORE_2:
668                         case JAVA_LSTORE_2:
669                         case JAVA_FSTORE_2:
670                         case JAVA_ASTORE_2:
671                                 readonly[2] = false;
672                                 break;
673
674                         case JAVA_ISTORE_3:
675                         case JAVA_LSTORE_3:
676                         case JAVA_FSTORE_3:
677                         case JAVA_ASTORE_3:
678                                 readonly[3] = false;
679                                 break;
680
681                         case JAVA_IINC:
682                                 if (!iswide) {
683                                         i = code_get_u1(p + 1,m);
684
685                                 } else {
686                                         i = code_get_u2(p + 1,m);
687                                 }
688                                 readonly[i] = false;
689                                 break;
690                         }
691                 }
692
693                 /*              for (i=lastlabel; i<=p; i++) label_index[i] = gp; 
694                                 printf("lastlabel=%d p=%d gp=%d\n",lastlabel, p, gp);
695                 lastlabel = p+1; */
696                 for (i = p; i < nextp; i++) label_index[i] = gp;
697
698                 if (opt_stat) { 
699                         if ((!isnotrootlevel) && !maxdepthHit) {
700                                 maxdepthHit = true;
701 #if defined(ENABLE_STATISTICS)
702                                 count_in_maxDepth++;
703 #endif
704                         }
705                         }
706                 if (isnotleaflevel) { 
707
708                         switch (opcode) {
709
710                         case JAVA_INVOKEINTERFACE:
711                         case JAVA_INVOKEVIRTUAL:
712                                 if (!inlinevirtuals) 
713                                         break;
714                         
715                         case JAVA_INVOKESPECIAL:
716                         case JAVA_INVOKESTATIC:
717                                 i = code_get_u2(p + 1,m);
718                                 {
719                                         constant_FMIref *imr;
720                                         methodinfo *imi;
721                                         classinfo *imrclass;
722
723                                         methodinfo *mout;
724                                         bool uniqueVirt= false;
725
726
727                                         if (opcode ==JAVA_INVOKEINTERFACE) {
728                                             imr = class_getconstant(m->class, i, CONSTANT_InterfaceMethodref);
729                                                 if (!imr)
730                                                         return NULL;
731                                                 if (!resolve_classref(m,imr->classref,resolveEager,true, true,&imrclass)) {
732                                                         log_text("Could not resolve class reference");
733                                                         assert(0);
734                                                 }
735                                             LAZYLOADING(imrclass)
736                                             imi = class_resolveinterfacemethod(
737                                                 imrclass,
738                                                 imr->name,
739                                                 imr->descriptor,
740                                                 m->class,
741                                                 true);
742                                             if (!imi) { /* extra for debug */
743                                                         log_text("ExceptionI thrown while parsing bytecode"); /* XXX should be passed on */
744                                                         assert(0);
745                                                 }
746
747                                         } else {
748                                                 imr = class_getconstant(m->class, i, CONSTANT_Methodref);
749                                                 if (!imr)
750                                                         return NULL;
751                                                 if (!resolve_classref(m,imr->classref,resolveEager,true, true,&imrclass)) {
752                                                         log_text("Could not resolve class reference");
753                                                         assert(0);
754                                                 }
755                                            LAZYLOADING(imrclass)
756                                            imi = class_resolveclassmethod(
757                                                 imrclass,
758                                                 imr->name,
759                                                 imr->descriptor,
760                                                 m->class,
761                                                 true);
762                                             if (!imi) { /* extra for debug */
763                                                         log_text("Exception0 thrown while parsing bytecode"); /* XXX should be passed on */
764                                                         assert(0);
765                                                 }
766                                             }
767
768                                         if (!imi) { /* normal-but never get here now */ 
769                                                 log_text("Exception thrown while parsing bytecode"); /* XXX should be passed on */
770                                                 assert(0);
771                                         }
772
773 /** Inlining has problem currently with typecheck & inlining **/
774 /** Due problem with typecheck & inlining, class checks fail for <init>s **/
775                                         if (utf_new_char("<init>") == imi->name) break; 
776                                         if (utf_new_char("finit$") == imi->name) break; 
777 /****/                                  
778                                         if (opcode == JAVA_INVOKEVIRTUAL) {
779                                                 mout = NULL;
780                                                 /* unique virt meth? then */
781                                                 /*  allow it to be inlined*/
782                                                 if (is_unique_method2(imi->class, imi, &mout) == 1) {
783                                                   if (mout != NULL) {
784                                                         imi = mout;
785                                                         uniqueVirt=true; 
786 #define INVIRTDEBUG
787 #ifdef INVIRTDEBUG
788                                                         METHINFOx(imi);
789                                                         printf("WAS unique virtual(-iv)\n");fflush(stdout);
790 #endif
791                                                         }
792                                                   } /* end is unique */
793                                                 } /* end INVOKEVIRTUAL */       
794                                         if (opcode == JAVA_INVOKEINTERFACE){
795                                                 mout = NULL; 
796 #ifdef INVIRTDEBUG
797                                                 METHINFOx(imi);
798 #endif
799                                                 if (is_unique_interface_method (imi,&mout)) {
800                                                      if (mout != NULL) {
801                                                         imi = mout;
802                                                         uniqueVirt=true;
803 #ifdef INVIRTDEBUG
804                                                           METHINFOx(imi);
805                                                           printf("WAS unique interface(-iv)\n");fflush(stdout);
806 #endif
807                                                         }
808                                                         
809                                                      } 
810                                                 } /* end INVOKEINTERFACE */     
811
812                                         if (can_inline(inline_env, m, imi, imr, uniqueVirt, opcode)) {
813                                                 inlining_methodinfo *tmp;
814                                                 method_descriptor2types(imi);
815
816                                                 inline_env->cummethods++;
817
818                                                 if (opt_verbose) 
819                                                         {char logtext[MAXLOGTEXT];
820                                                         printf("Going to inline: ");
821                                                         METHINFOj(imi) 
822                                                         printf("\nFrom "); fflush(stdout); METHINFOj(m)
823                                                         sprintf(logtext, "Going to inline: ");
824                                                         utf_sprint(logtext  +strlen(logtext), imi->class->name);
825                                                         strcpy(logtext + strlen(logtext), ".");
826                                                         utf_sprint(logtext + strlen(logtext), imi->name);
827                                                         utf_sprint(logtext + strlen(logtext), imi->descriptor);
828                                                         log_text(logtext);
829                                                         sprintf(logtext,"<%i>",imi->jcodelength);
830                                                         log_text(logtext);
831                                                         if ( (!(opcode == JAVA_INVOKEVIRTUAL)) &&
832                                                              (! ( (imi->flags & ACC_STATIC )
833                                                              ||   ((imi->flags & ACC_PRIVATE) && (imi->class == inline_env->class))
834                                                              ||   (imi->flags & ACC_FINAL  ))) )
835                                                            {
836                                                            printf("DEBUG WARNING:PROBABLE INLINE PROBLEM flags not static, private or final for non-virtual inlined method\n"); fflush(stdout);
837                                                            METHINFOx(imi);
838                                                            log_text("PROBABLE INLINE PROBLEM flags not static, private or final for non-virtual inlined method\n See method info after DEBUG WARNING\n");
839                                                            }
840
841                                                 }
842                                                 
843                                                 tmp =inlining_analyse_method(imi, level + 1, gp, firstlocal + m->maxlocals, maxstackdepth + m->maxstack, inline_env);
844                                                 list_addlast(newnode->inlinedmethods, tmp);
845                 #ifdef DEBUGi
846 printf("New node Right after an inline by:");fflush(stdout);
847 METHINFOj(m)
848 print_inlining_methodinfo(newnode);
849 printf("end new node\n"); fflush(stdout);
850                 #endif
851                                                 gp = tmp->stopgp;
852                                                 p = nextp;
853                                         }
854                                 }
855                                 break;
856                         }
857                 }  
858         } /* for */
859         
860         newnode->stopgp = gp;
861         label_index[jcodelength]=gp;
862     return newnode;
863 }
864
865 /* --------------------------------------------------------------------*/
866 /*  print_ functions: check inline structures contain what is expected */
867 /* --------------------------------------------------------------------*/
868 void print_t_inlining_globals (t_inlining_globals *g) 
869 {
870 printf("\n------------\nt_inlining_globals struct for: \n\t");fflush(stdout); 
871 METHINFOj(g->method);
872 printf("\tclass=");fflush(stdout);
873   utf_display(g->class->name);printf("\n");fflush(stdout);
874
875 printf("\tjcodelength=%i; jcode=%p;\n",g->jcodelength, g->jcode);
876
877 if (g->isinlinedmethod==true) {
878   printf("\tisinlinedmethod=true ");fflush(stdout);  
879   }
880 else {
881   printf("\tisinlinedmethod=false");fflush(stdout);  
882   }
883
884 printf("\tcumjcodelength=%i ,cummaxstack=%i ,cumextablelength=%i ",
885  g->cumjcodelength,    g->cummaxstack,  g->cumextablelength);fflush(stdout);
886 printf("\tcumlocals=%i ,cummethods=%i \n",
887  g->cumlocals,    g->cummethods);fflush(stdout);  
888
889 printf("s>s>s> ");fflush(stdout);
890         print_inlining_stack     (g->inlining_stack);
891 printf("i>i>i> "); fflush(stdout);
892         print_inlining_methodinfo(g->inlining_rootinfo);
893 printf("-------------------\n");fflush(stdout);
894 }
895
896 /* --------------------------------------------------------------------*/
897 void print_inlining_stack     ( list                *s)
898 {
899   t_inlining_stacknode *is;
900
901 if (s==NULL) { 
902   printf("\n\tinlining_stack: NULL\n");
903   return;
904   }
905
906 /* print first  element to see if get into stack */
907 printf("\n\tinlining_stack: NOT NULL\n");
908
909 is=list_first(s); 
910 if (is==NULL) { 
911     printf("\n\tinlining_stack = init'd but EMPTY\n");
912     fflush(stdout);
913     return;
914     }
915
916 printf("\n\tinlining_stack: NOT NULL\n");
917
918 for (is=list_first(s); 
919        is!=NULL;
920        is=list_next(s,is)) {
921          printf("\n\ti>--->inlining_stack entry: \n"); fflush(stdout);
922          METHINFOx(is->method);
923          printf("i=%i, p=%i, nextp=%i, opcode=%i;\n",
924                 is->i,is->p,is->nextp,is->opcode);fflush(stdout);
925          print_inlining_methodinfo(is->inlinfo);
926     } /*end for */
927 }
928
929 /* --------------------------------------------------------------------*/
930 void print_inlining_methodinfo( inlining_methodinfo *r) {
931   int i=0;
932   int cnt,cnt2;
933   inlining_methodinfo *im;
934   inlining_methodinfo *im2;
935   bool labellong = false;
936
937 if (r==NULL) { 
938   printf("\n\tinlining_methodinfo: NULL\n");
939   return;
940   }
941 printf("\n\tinlining_methodinfo for:"); fflush(stdout);
942
943 if (r->method != NULL) {
944   utf_display(r->method->class->name); printf("."); fflush(stdout); \
945   method_println(r->method); fflush(stdout); \
946   }
947 else {
948   printf(" NULL!!!!!\n");fflush(stdout);
949   }
950
951 if (r->readonly==NULL) {
952   printf("\treadonly==NULL ");fflush(stdout);  
953   }
954 else {
955   printf("\treadonly=");fflush(stdout);  
956   for (i = 0; i < r->method->maxlocals; i++)  {
957     if (r->readonly[i] == true)
958       printf("[i]=T;");
959     else
960       printf("[i]=F;");
961     fflush(stdout);
962     } 
963   }
964
965 /**printf("\tstartgp=%i; stopgp=%i; firstlocal=%i; label_index=%p;\n", **/
966 printf("\tstartgp=%i; stopgp=%i; firstlocal=%i; label_index=%p;\n",
967           r->startgp, r->stopgp, r->firstlocal, (void *)r->label_index);
968 printf ("label_index[0..%d]->", r->method->jcodelength);
969 if (labellong) {
970 for (i=0; i<r->method->jcodelength; i++) printf ("%d:%d ", i, r->label_index[i]); }
971 else {
972 printf ("%d:%d ", 0, r->label_index[i]);
973 printf ("%d:%d ", 
974   (r->method->jcodelength-1), r->label_index[r->method->jcodelength-1]);
975 }
976
977 printf("\n:::::inlines::::::::::::::::::::\n");
978 if (list_first(r->inlinedmethods) == NULL) {
979         printf("Nothing\n");fflush(stdout);
980         }
981 else {
982         for (im=list_first(r->inlinedmethods),cnt=0; 
983              im!=NULL;
984              im=list_next(r->inlinedmethods,im),cnt++) {
985                 printf("*"); fflush(stdout);
986                 printf("%i:",cnt);
987                 printf("[1L%i] ",im->firstlocal); fflush(stdout);
988                 METHINFOj(im->method)
989                 printf("::::: which inlines::"); fflush(stdout);        
990                 if (list_first(im->inlinedmethods) == NULL) {
991                         printf("Nothing\n");fflush(stdout);
992                         }
993                 else   {
994                         printf("##"); fflush(stdout);
995                         for (im2=list_first(im->inlinedmethods),cnt2=0; 
996                              im2!=NULL;
997                              im2=list_next(im2->inlinedmethods,im2),cnt2++) 
998                                 {
999                                 printf("\t%i::",cnt2); fflush(stdout);
1000                                 printf("[1L%i] ",im2->firstlocal); 
1001                                         fflush(stdout);
1002                                 METHINFOj(im2->method)
1003                                 }
1004                         printf("\n"); fflush(stdout);
1005                         }
1006                 } 
1007       }
1008 }
1009
1010
1011 /*
1012  * These are local overrides for various environment variables in Emacs.
1013  * Please do not remove this and leave it at the end of the file, where
1014  * Emacs will automagically detect them.
1015  * ---------------------------------------------------------------------
1016  * Local variables:
1017  * mode: c
1018  * indent-tabs-mode: t
1019  * c-basic-offset: 4
1020  * tab-width: 4
1021  * End:
1022  */