tableswitch index problem solved, jump to wrong instruction of inlined functions...
[cacao.git] / src / vm / jit / inline / inline.c
1 /* jit/inline.c - code inliner
2
3 globals moved to structure and passed as parameter
4
5    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
6    R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
7    M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
8    P. Tomsich, J. Wenninger
9
10    This file is part of CACAO.
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License as
14    published by the Free Software Foundation; either version 2, or (at
15    your option) any later version.
16
17    This program is distributed in the hope that it will be useful, but
18    WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20    General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software
24    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25    02111-1307, USA.
26
27    Contact: cacao@complang.tuwien.ac.at
28
29    Authors: Dieter Thuernbeck
30
31    $Id: inline.c 1432 2004-11-03 12:14:50Z jowenn $
32
33 */
34
35
36 #include <stdio.h>
37 #include <string.h>
38 #include "global.h"
39 #include "loader.h"
40 #include "tables.h"
41 #include "options.h"
42 #include "jit/inline.h"
43 #include "jit/jit.h"
44 #include "jit/parse.h"
45 #include "toolbox/logging.h"
46 #include "toolbox/memory.h"
47
48 #define METHINFO(m) \
49   utf_display(m->class->name); printf("."); fflush(stdout); \
50   method_display(m); fflush(stdout); \
51
52 #define IMETHINFO(m) \
53   utf_display(m->class->name); printf("."); fflush(stdout); \
54   method_display(m); fflush(stdout); \
55   printf("\tm->jcodelength=%i; ",m->jcodelength); fflush(stdout); \
56   printf("m->jcode=%p;\n",m->jcode); fflush(stdout); \
57   printf("\tm->maxlocals=%i; ",m->maxlocals); fflush(stdout); \
58   printf("m->maxstack=%i;\n",m->maxstack); fflush(stdout);
59
60 bool DEBUGi = false;
61 // checked functions and macros: LOADCONST code_get OP1 BUILTIN block_insert bound_check ALIGN
62
63 // replace jcodelength loops with correct number after main for loop in parse()!
64
65 /*-----------------------------------------------------------*/
66 /* just initialize global structure for non-inlining         */
67 /*-----------------------------------------------------------*/
68
69 t_inlining_globals *inlining_init0(methodinfo *m, 
70                                    t_inlining_globals *inline_env)
71 {
72  /* initialization for normal use in parse */
73         inlining_set_compiler_variables_fun(m, inline_env);
74         inline_env->isinlinedmethod = 0;
75         inline_env->cumjcodelength = m->jcodelength; /* for not inlining */
76         inline_env->cummaxstack = m->maxstack; /*why has here been 0 ? */
77         inline_env->cumextablelength = 0;
78         inline_env->cumlocals = m->maxlocals;
79         inline_env->cummethods = 0;//co not global or static-used only here?
80         inline_env->inlining_stack = NULL;
81         inline_env->inlining_rootinfo = NULL;
82 return inline_env;
83 }
84 /*-----------------------------------------------------------*/
85
86 t_inlining_globals *inlining_init(methodinfo *m)
87 {
88         t_inlining_globals *inline_env = DNEW(t_inlining_globals);
89         inlining_init0(m,inline_env);
90 if (useinlining)
91         {
92 if (DEBUGi==true) {
93                 printf("\n-------- Inlining init for: "); fflush(stdout);
94                 IMETHINFO(m)
95                 }
96         inline_env->cumjcodelength = 0;
97         inline_env->inlining_stack = NEW(list);
98         list_init(inline_env->inlining_stack, 
99                   OFFSET(t_inlining_stacknode, linkage));
100         /*------ analyze ------*/
101 if (DEBUGi==true) {print_t_inlining_globals(inline_env);}
102         inline_env->inlining_rootinfo 
103                 = inlining_analyse_method(m, 0, 0, 0, 0, inline_env);
104 if (DEBUGi==true) {print_t_inlining_globals(inline_env);}
105         /*---------------------*/
106         //if (inline_env->cummethods == 0) {
107         //  inline_env = DNEW(t_inlining_globals);
108         //  inlining_init0(m,inline_env);
109         //  return inline_env;
110         //  }
111 if (DEBUGi==true) {
112   printf("(l,s) (%i,%i) was (%i,%i)\n",
113     m->maxlocals, inline_env->cumlocals,
114     m->maxstack,  inline_env->cummaxstack); fflush(stdout);
115   }
116 #if 0
117 /*This looks wrong*/
118         m->maxlocals = inline_env->cumlocals;   //orig not used
119         m->maxstack = inline_env->cummaxstack;  //orig global maxstack var!!
120 #endif
121 //panic("TEMP so can test just inline init\n");
122         }
123 return inline_env;
124 }
125
126
127 void inlining_cleanup(t_inlining_globals *inline_env)
128 {
129         FREE(inline_env->inlining_stack, t_inlining_stacknode);
130 }
131
132
133 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)
134 {
135         t_inlining_stacknode *new = NEW(t_inlining_stacknode);
136
137         new->i = i;
138         new->p = p;
139         new->nextp = nextp;
140         new->opcode = opcode;
141         new->method = inline_env->method;
142         new->lineindex=lineindex;
143         new->currentline=currentline;
144         new->linepcchange=linepcchange;
145         new->inlinfo = inlinfo;
146         list_addfirst(inline_env->inlining_stack, new);
147         inline_env->isinlinedmethod++;
148 }
149
150
151 void inlining_pop_compiler_variables(
152                                     int *i, int *p, int *nextp,
153                                     int *opcode, u2 *lineindex,
154                                     u2 *currentline,u2 *linepcchange,
155                                     inlining_methodinfo **inlinfo,
156                                     t_inlining_globals *inline_env)
157 {
158         t_inlining_stacknode *tmp 
159           = (t_inlining_stacknode *) list_first(inline_env->inlining_stack);
160
161         if (!inline_env->isinlinedmethod) panic("Attempting to pop from inlining stack in toplevel method!\n");
162
163         *i = tmp->i;
164         *p = tmp->p;
165         *nextp = tmp->nextp;
166         *opcode = tmp->opcode;
167
168         *lineindex=tmp->lineindex;
169         *currentline=tmp->currentline;
170         *currentline=tmp->linepcchange;
171
172         *inlinfo = tmp->inlinfo;
173
174         inline_env->method = tmp->method; /*co*/
175         inline_env->class = inline_env->method->class; /*co*/
176         inline_env->jcodelength = inline_env->method->jcodelength; /*co*/
177         inline_env->jcode = inline_env->method->jcode; /*co*/
178
179         list_remove(inline_env->inlining_stack, tmp);
180         FREE(tmp, t_inlining_stacknode);
181         inline_env->isinlinedmethod--;
182 }
183
184
185 void inlining_set_compiler_variables_fun(methodinfo *m,
186                                          t_inlining_globals *inline_env)
187 {
188         /* XXX TWISTI */
189         inline_env->method = m; /*co*/
190         inline_env->class  = m->class; /*co*/
191         inline_env->jcode  = m->jcode; /*co*/
192         inline_env->jcodelength = m->jcodelength; /*co*/
193 }
194
195
196 classinfo *first_occurence(classinfo* class, utf* name, utf* desc)
197 {
198         classinfo *first = class;
199         
200         for (; class->super != NULL ; class = class->super) {
201                 if (class_findmethod(class->super, name, desc) != NULL) {
202                         first = class->super;
203                 }                       
204         }
205
206         return first;
207 }
208
209
210 bool is_unique_rec(classinfo *class, methodinfo *m, utf* name, utf* desc)
211 {
212         methodinfo *tmp = class_findmethod(class, name, desc);
213         if ((tmp != NULL) && (tmp != m))
214                 return false;
215
216         for (; class != NULL; class = class->nextsub) {
217                 if ((class->sub != NULL) && !is_unique_rec(class->sub, m, name, desc)) {
218                         return false; 
219                 }
220         }
221         return true;
222 }
223
224
225 bool is_unique_method(classinfo *class, methodinfo *m, utf* name, utf* desc)
226 {
227         classinfo *firstclass;
228         
229         /*      sprintf (logtext, "First occurence of: ");
230         utf_sprint (logtext+strlen(logtext), m->class->name);
231         strcpy (logtext+strlen(logtext), ".");
232         utf_sprint (logtext+strlen(logtext), m->name);
233         utf_sprint (logtext+strlen(logtext), m->descriptor);
234         dolog (); */
235         
236         firstclass = first_occurence(class, name, desc);
237         
238         /*      sprintf (logtext, "\nis in class:");
239         utf_sprint (logtext+strlen(logtext), firstclass->name);
240         dolog (); */
241
242         if (firstclass != class) return false;
243
244         return is_unique_rec(class, m, name, desc);
245 }
246
247 inlining_methodinfo *inlining_analyse_method(methodinfo *m, 
248                                           int level, int gp, 
249                                           int firstlocal, int maxstackdepth,
250                                           t_inlining_globals *inline_env)
251 {
252         inlining_methodinfo *newnode = DNEW(inlining_methodinfo);
253         /*u1 *jcode = m->jcode;*/
254         int jcodelength = m->jcodelength;
255         int p;
256         int nextp;
257         int opcode;
258         int i;
259         bool iswide = false, oldiswide;
260         bool *readonly = NULL;
261         int  *label_index = NULL;
262         bool isnotrootlevel = (level > 0);
263         bool isnotleaflevel = (level < INLINING_MAXDEPTH);
264
265         //      if (level == 0) gp = 0;
266         /*
267         sprintf (logtext, "Performing inlining analysis of: ");
268         utf_sprint (logtext+strlen(logtext), m->class->name);
269         strcpy (logtext+strlen(logtext), ".");
270         utf_sprint (logtext+strlen(logtext), m->name);
271         utf_sprint (logtext+strlen(logtext), m->descriptor);
272         dolog (); */
273
274         if (isnotrootlevel) {
275                 newnode->readonly = readonly = DMNEW(bool, m->maxlocals); //FIXME only paramcount entrys necessary
276                 for (i = 0; i < m->maxlocals; readonly[i++] = true);
277                 isnotrootlevel = true;
278
279         } else {
280                 readonly = NULL;
281         }
282         
283         label_index = DMNEW(int, jcodelength+200);
284
285         newnode->inlinedmethods = DNEW(list);
286         list_init(newnode->inlinedmethods, OFFSET(inlining_methodinfo, linkage));
287
288         newnode->method = m;
289         newnode->startgp = gp;
290         newnode->readonly = readonly;
291         newnode->label_index = label_index;
292         newnode->firstlocal = firstlocal;
293         inline_env->cumjcodelength += jcodelength + m->paramcount + 1 + 5;
294
295         if ((firstlocal + m->maxlocals) > inline_env->cumlocals) {
296                 inline_env->cumlocals = firstlocal + m->maxlocals;
297         }
298
299         if ((maxstackdepth + m->maxstack) > inline_env->cummaxstack) {
300                 inline_env->cummaxstack = maxstackdepth + m->maxstack;
301         }
302
303         inline_env->cumextablelength += m->exceptiontablelength;
304    
305
306         for (p = 0; p < jcodelength; gp += (nextp - p), p = nextp) {
307                 opcode = code_get_u1 (p,m);
308                 nextp = p + jcommandsize[opcode];
309                 oldiswide = iswide;
310
311                 /* figure out nextp */
312
313                 switch (opcode) {
314                 case JAVA_ILOAD:
315                 case JAVA_LLOAD:
316                 case JAVA_FLOAD:
317                 case JAVA_DLOAD:
318                 case JAVA_ALOAD: 
319
320                 case JAVA_ISTORE:
321                 case JAVA_LSTORE:
322                 case JAVA_FSTORE:
323                 case JAVA_DSTORE:
324                 case JAVA_ASTORE: 
325
326                 case JAVA_RET:
327                         if (iswide) {
328                                 nextp = p + 3;
329                                 iswide = false;
330                         }
331                         break;
332
333                 case JAVA_IINC:
334                         if (iswide) {
335                                 nextp = p + 5;
336                                 iswide = false;
337                         }
338                         break;
339
340                 case JAVA_WIDE:
341                         iswide = true;
342                         nextp = p + 1;
343                         break;
344
345                 case JAVA_LOOKUPSWITCH:
346                         nextp = ALIGN((p + 1), 4) + 4;
347                         nextp += code_get_u4(nextp,m) * 8 + 4;
348                         break;
349
350                 case JAVA_TABLESWITCH:
351                         nextp = ALIGN((p + 1), 4) + 4;
352                         nextp += (code_get_u4(nextp+4,m) - code_get_u4(nextp,m) + 1) * 4 + 4 +4;
353                         break;
354                 }
355
356                 /* detect readonly variables in inlined methods */
357                 
358                 if (isnotrootlevel) { 
359                         bool iswide = oldiswide;
360                         
361                         switch (opcode) {
362                         case JAVA_ISTORE:
363                         case JAVA_LSTORE:
364                         case JAVA_FSTORE:
365                         case JAVA_DSTORE:
366                         case JAVA_ASTORE: 
367                                 if (!iswide) {
368                                         i = code_get_u1(p + 1,m);
369
370                                 } else {
371                                         i = code_get_u2(p + 1,m);
372                                 }
373                                 readonly[i] = false;
374                                 break;
375
376                         case JAVA_ISTORE_0:
377                         case JAVA_LSTORE_0:
378                         case JAVA_FSTORE_0:
379                         case JAVA_ASTORE_0:
380                                 readonly[0] = false;
381                                 break;
382
383                         case JAVA_ISTORE_1:
384                         case JAVA_LSTORE_1:
385                         case JAVA_FSTORE_1:
386                         case JAVA_ASTORE_1:
387                                 readonly[1] = false;
388                                 break;
389
390                         case JAVA_ISTORE_2:
391                         case JAVA_LSTORE_2:
392                         case JAVA_FSTORE_2:
393                         case JAVA_ASTORE_2:
394                                 readonly[2] = false;
395                                 break;
396
397                         case JAVA_ISTORE_3:
398                         case JAVA_LSTORE_3:
399                         case JAVA_FSTORE_3:
400                         case JAVA_ASTORE_3:
401                                 readonly[3] = false;
402                                 break;
403
404                         case JAVA_IINC:
405                                 if (!iswide) {
406                                         i = code_get_u1(p + 1,m);
407
408                                 } else {
409                                         i = code_get_u2(p + 1,m);
410                                 }
411                                 readonly[i] = false;
412                                 break;
413                         }
414                 }
415
416                 /*              for (i=lastlabel; i<=p; i++) label_index[i] = gp; 
417                 //              printf("lastlabel=%d p=%d gp=%d\n",lastlabel, p, gp);
418                 lastlabel = p+1; */
419                 for (i = p; i < nextp; i++) label_index[i] = gp;
420
421                 if (isnotleaflevel) { 
422
423                         switch (opcode) {
424                         case JAVA_INVOKEVIRTUAL:
425                                 if (!inlinevirtuals)
426                                         break;
427                         case JAVA_INVOKESTATIC:
428                                 i = code_get_u2(p + 1,m);
429                                 {
430                                         constant_FMIref *imr;
431                                         methodinfo *imi;
432
433                                         imr = class_getconstant(m->class, i, CONSTANT_Methodref);
434
435                                         if (!class_load(imr->class))
436                                                 return NULL;
437
438                                         if (!class_link(imr->class))
439                                                 return NULL;
440
441                                         imi = class_resolveclassmethod(imr->class,
442                                                                                                    imr->name,
443                                                                                                    imr->descriptor,
444                                                                                                    m->class,
445                                                                                                    true);
446
447                                         if (!imi)
448                                                 panic("Exception thrown while parsing bytecode"); /* XXX should be passed on */
449
450                                         if (opcode == JAVA_INVOKEVIRTUAL) {
451                                                 if (!is_unique_method(imi->class, imi, imr->name, imr->descriptor))
452                                                         break;
453                                         }
454
455                                         /*if (imi->flags & ACC_NATIVE) log_text("Native method,no inlining");*/
456                                         if ((inline_env->cummethods < INLINING_MAXMETHODS) &&
457                                                 (!(imi->flags & ACC_NATIVE)) &&  
458                                                 (!inlineoutsiders || (m->class == imr->class)) && 
459                                                 (imi->jcodelength < INLINING_MAXCODESIZE) && 
460                                                 (imi->jcodelength > 0) && 
461                                                 (inlineexceptions || (imi->exceptiontablelength == 0))) { //FIXME: eliminate empty methods?
462                                                 inlining_methodinfo *tmp;
463                                                 descriptor2types(imi);
464
465                                                 inline_env->cummethods++;
466
467                                                 if (verbose) {
468                                                         char logtext[MAXLOGTEXT];
469                                                         sprintf(logtext, "Going to inline: ");
470                                                         utf_sprint(logtext  +strlen(logtext), imi->class->name);
471                                                         strcpy(logtext + strlen(logtext), ".");
472                                                         utf_sprint(logtext + strlen(logtext), imi->name);
473                                                         utf_sprint(logtext + strlen(logtext), imi->descriptor);
474                                                         log_text(logtext);
475                                                 }
476                                                 
477                                                 tmp =inlining_analyse_method(imi, level + 1, gp, firstlocal + m->maxlocals, maxstackdepth + m->maxstack, inline_env);
478                                                 list_addlast(newnode->inlinedmethods, tmp);
479                                                 gp = tmp->stopgp;
480                                                 p = nextp;
481                                         }
482                                 }
483                                 break;
484                         }
485                 }  
486         } /* for */
487         
488         newnode->stopgp = gp;
489
490         if (DEBUGi==true) {
491           printf ("\nResult of inlining analysis of: ");
492           IMETHINFO(m);
493           printf("was called by:\n"); fflush(stdout);
494           IMETHINFO(inline_env->method);
495           printf ("label_index[0..%d]->", jcodelength);
496           for (i=0;i<jcodelength; i++) printf ("%d:%d ", i, label_index[i]);
497           printf("stopgp : %d\n",newnode->stopgp); 
498           }
499
500     return newnode;
501 }
502
503 /* --------------------------------------------------------------------*/
504 /*  print_ functions: check inline structures contain what is expected */
505 /* --------------------------------------------------------------------*/
506 void print_t_inlining_globals (t_inlining_globals *g) 
507 {
508 printf("\n------------\nt_inlining_globals struct for: \n\t");fflush(stdout); 
509 METHINFO(g->method);
510 printf("\tclass=");fflush(stdout);
511   utf_display(g->class->name);printf("\n");fflush(stdout);
512
513 printf("\tjcodelength=%i; jcode=%p;\n",g->jcodelength, g->jcode);
514
515 if (g->isinlinedmethod==true) {
516   printf("\tisinlinedmethod=true ");fflush(stdout);  
517   }
518 else {
519   printf("\tisinlinedmethod=false");fflush(stdout);  
520   }
521
522 printf("\tcumjcodelength=%i ,cummaxstack=%i ,cumextablelength=%i ",
523  g->cumjcodelength,    g->cummaxstack,  g->cumextablelength);fflush(stdout);
524 printf("\tcumlocals=%i ,cummethods=%i \n",
525  g->cumlocals,    g->cummethods);fflush(stdout);  
526
527 printf("s>s>s> ");fflush(stdout);
528 print_inlining_stack     (g->inlining_stack);
529 printf("i>i>i> "); fflush(stdout);
530 print_inlining_methodinfo(g->inlining_rootinfo);
531 printf("-------------------\n");fflush(stdout);
532 }
533
534 /* --------------------------------------------------------------------*/
535 void print_inlining_stack     ( list                *s)
536 {
537 if (s==NULL) { 
538   printf("\n\tinlining_stack: NULL\n");
539   return;
540   }
541   
542   {/* print first  element to see if get into stack */
543   t_inlining_stacknode *is;
544   printf("\n\tinlining_stack: NOT NULL\n");
545
546   is=list_first(s); 
547   if (is==NULL) { 
548     printf("\n\tinlining_stack = init'd but EMPTY\n");
549     fflush(stdout);
550     return;
551     }
552   }
553
554   {
555   t_inlining_stacknode *is;
556   printf("\n\tinlining_stack: NOT NULL\n");
557
558
559   for (is=list_first(s); 
560        is!=NULL;
561        is=list_next(s,is)) {
562          printf("\n\ti>--->inlining_stack entry: \n"); fflush(stdout);
563          METHINFO(is->method);
564          printf("i=%i, p=%i, nextp=%i, opcode=%i;\n",
565                 is->i,is->p,is->nextp,is->opcode);fflush(stdout);
566          print_inlining_methodinfo(is->inlinfo);
567     } /*end for */
568   } 
569
570 }
571
572 /* --------------------------------------------------------------------*/
573 void print_inlining_methodinfo( inlining_methodinfo *r) {
574 if (r==NULL) { 
575   printf("\n\tinlining_methodinfo: NULL\n");
576   return;
577   }
578
579 if (r->method != NULL) {
580   utf_display(r->method->class->name); printf("."); fflush(stdout); \
581   method_display(r->method); fflush(stdout); \
582   }
583 else {
584   printf("method is NULL!!!!!\n");fflush(stdout);
585   }
586
587 printf("\n\tinlining_methodinfo for:"); fflush(stdout);
588 if (r->readonly==NULL) {
589   printf("\treadonly==NULL ");fflush(stdout);  
590   }
591 else {
592   int i;
593   printf("\treadonly=");fflush(stdout);  
594   for (i = 0; i < r->method->maxlocals; i++)  {
595     if (r->readonly[i] == true)
596       printf("[i]=T;");
597     else
598       printf("[i]=F;");
599     fflush(stdout);
600     } 
601   }
602
603
604 printf("\tstartgp=%i; stopgp=%i; firstlocal=%i; label_index=%p;\n",
605           r->startgp, r->stopgp, r->firstlocal, r->label_index);
606 {int i;
607 printf ("label_index[0..%d]->", r->method->jcodelength);
608 for (i=0; i<r->method->jcodelength; i++) printf ("%d:%d ", i, r->label_index[i]);
609 }
610
611 {
612 inlining_methodinfo *im;
613 for (im=list_first(r->inlinedmethods); 
614      im!=NULL;
615      im=list_next(r->inlinedmethods,im)) {
616   } 
617 }
618 }
619
620
621 /*
622  * These are local overrides for various environment variables in Emacs.
623  * Please do not remove this and leave it at the end of the file, where
624  * Emacs will automagically detect them.
625  * ---------------------------------------------------------------------
626  * Local variables:
627  * mode: c
628  * indent-tabs-mode: t
629  * c-basic-offset: 4
630  * tab-width: 4
631  * End:
632  */