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