1f59f473b59202c6fd1d892c62d9b53bd5080838
[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 1415 2004-10-11 20:12:08Z 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 = 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         m->maxlocals = inline_env->cumlocals;   //orig not used
117         m->maxstack = inline_env->cummaxstack;  //orig global maxstack var!!
118
119 //panic("TEMP so can test just inline init\n");
120         }
121 return inline_env;
122 }
123
124
125 void inlining_cleanup(t_inlining_globals *inline_env)
126 {
127         FREE(inline_env->inlining_stack, t_inlining_stacknode);
128 }
129
130
131 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)
132 {
133         t_inlining_stacknode *new = NEW(t_inlining_stacknode);
134
135         new->i = i;
136         new->p = p;
137         new->nextp = nextp;
138         new->opcode = opcode;
139         new->method = inline_env->method;
140         new->lineindex=lineindex;
141         new->currentline=currentline;
142         new->linepcchange=linepcchange;
143         new->inlinfo = inlinfo;
144         list_addfirst(inline_env->inlining_stack, new);
145         inline_env->isinlinedmethod++;
146 }
147
148
149 void inlining_pop_compiler_variables(
150                                     int *i, int *p, int *nextp,
151                                     int *opcode, u2 *lineindex,
152                                     u2 *currentline,u2 *linepcchange,
153                                     inlining_methodinfo **inlinfo,
154                                     t_inlining_globals *inline_env)
155 {
156         t_inlining_stacknode *tmp 
157           = (t_inlining_stacknode *) list_first(inline_env->inlining_stack);
158
159         if (!inline_env->isinlinedmethod) panic("Attempting to pop from inlining stack in toplevel method!\n");
160
161         *i = tmp->i;
162         *p = tmp->p;
163         *nextp = tmp->nextp;
164         *opcode = tmp->opcode;
165
166         *lineindex=tmp->lineindex;
167         *currentline=tmp->currentline;
168         *currentline=tmp->linepcchange;
169
170         *inlinfo = tmp->inlinfo;
171
172         inline_env->method = tmp->method; /*co*/
173         inline_env->class = inline_env->method->class; /*co*/
174         inline_env->jcodelength = inline_env->method->jcodelength; /*co*/
175         inline_env->jcode = inline_env->method->jcode; /*co*/
176
177         list_remove(inline_env->inlining_stack, tmp);
178         FREE(tmp, t_inlining_stacknode);
179         inline_env->isinlinedmethod--;
180 }
181
182
183 void inlining_set_compiler_variables_fun(methodinfo *m,
184                                          t_inlining_globals *inline_env)
185 {
186         /* XXX TWISTI */
187         inline_env->method = m; /*co*/
188         inline_env->class  = m->class; /*co*/
189         inline_env->jcode  = m->jcode; /*co*/
190         inline_env->jcodelength = m->jcodelength; /*co*/
191 }
192
193
194 classinfo *first_occurence(classinfo* class, utf* name, utf* desc)
195 {
196         classinfo *first = class;
197         
198         for (; class->super != NULL ; class = class->super) {
199                 if (class_findmethod(class->super, name, desc) != NULL) {
200                         first = class->super;
201                 }                       
202         }
203
204         return first;
205 }
206
207
208 bool is_unique_rec(classinfo *class, methodinfo *m, utf* name, utf* desc)
209 {
210         methodinfo *tmp = class_findmethod(class, name, desc);
211         if ((tmp != NULL) && (tmp != m))
212                 return false;
213
214         for (; class != NULL; class = class->nextsub) {
215                 if ((class->sub != NULL) && !is_unique_rec(class->sub, m, name, desc)) {
216                         return false; 
217                 }
218         }
219         return true;
220 }
221
222
223 bool is_unique_method(classinfo *class, methodinfo *m, utf* name, utf* desc)
224 {
225         classinfo *firstclass;
226         
227         /*      sprintf (logtext, "First occurence of: ");
228         utf_sprint (logtext+strlen(logtext), m->class->name);
229         strcpy (logtext+strlen(logtext), ".");
230         utf_sprint (logtext+strlen(logtext), m->name);
231         utf_sprint (logtext+strlen(logtext), m->descriptor);
232         dolog (); */
233         
234         firstclass = first_occurence(class, name, desc);
235         
236         /*      sprintf (logtext, "\nis in class:");
237         utf_sprint (logtext+strlen(logtext), firstclass->name);
238         dolog (); */
239
240         if (firstclass != class) return false;
241
242         return is_unique_rec(class, m, name, desc);
243 }
244
245 inlining_methodinfo *inlining_analyse_method(methodinfo *m, 
246                                           int level, int gp, 
247                                           int firstlocal, int maxstackdepth,
248                                           t_inlining_globals *inline_env)
249 {
250         inlining_methodinfo *newnode = DNEW(inlining_methodinfo);
251         /*u1 *jcode = m->jcode;*/
252         int jcodelength = m->jcodelength;
253         int p;
254         int nextp;
255         int opcode;
256         int i;
257         bool iswide = false, oldiswide;
258         bool *readonly = NULL;
259         int  *label_index = NULL;
260         bool isnotrootlevel = (level > 0);
261         bool isnotleaflevel = (level < INLINING_MAXDEPTH);
262
263         //      if (level == 0) gp = 0;
264         /*
265         sprintf (logtext, "Performing inlining analysis of: ");
266         utf_sprint (logtext+strlen(logtext), m->class->name);
267         strcpy (logtext+strlen(logtext), ".");
268         utf_sprint (logtext+strlen(logtext), m->name);
269         utf_sprint (logtext+strlen(logtext), m->descriptor);
270         dolog (); */
271
272         if (isnotrootlevel) {
273                 newnode->readonly = readonly = DMNEW(bool, m->maxlocals); //FIXME only paramcount entrys necessary
274                 for (i = 0; i < m->maxlocals; readonly[i++] = true);
275                 isnotrootlevel = true;
276
277         } else {
278                 readonly = NULL;
279         }
280         
281         label_index = DMNEW(int, jcodelength+200);
282
283         newnode->inlinedmethods = DNEW(list);
284         list_init(newnode->inlinedmethods, OFFSET(inlining_methodinfo, linkage));
285
286         newnode->method = m;
287         newnode->startgp = gp;
288         newnode->readonly = readonly;
289         newnode->label_index = label_index;
290         newnode->firstlocal = firstlocal;
291         inline_env->cumjcodelength += jcodelength + m->paramcount + 1 + 5;
292
293         if ((firstlocal + m->maxlocals) > inline_env->cumlocals) {
294                 inline_env->cumlocals = firstlocal + m->maxlocals;
295         }
296
297         if ((maxstackdepth + m->maxstack) > inline_env->cummaxstack) {
298                 inline_env->cummaxstack = maxstackdepth + m->maxstack;
299         }
300
301         inline_env->cumextablelength += m->exceptiontablelength;
302    
303
304         for (p = 0; p < jcodelength; gp += (nextp - p), p = nextp) {
305                 opcode = code_get_u1 (p,m);
306                 nextp = p + jcommandsize[opcode];
307                 oldiswide = iswide;
308
309                 /* figure out nextp */
310
311                 switch (opcode) {
312                 case JAVA_ILOAD:
313                 case JAVA_LLOAD:
314                 case JAVA_FLOAD:
315                 case JAVA_DLOAD:
316                 case JAVA_ALOAD: 
317
318                 case JAVA_ISTORE:
319                 case JAVA_LSTORE:
320                 case JAVA_FSTORE:
321                 case JAVA_DSTORE:
322                 case JAVA_ASTORE: 
323
324                 case JAVA_RET:
325                         if (iswide) {
326                                 nextp = p + 3;
327                                 iswide = false;
328                         }
329                         break;
330
331                 case JAVA_IINC:
332                         if (iswide) {
333                                 nextp = p + 5;
334                                 iswide = false;
335                         }
336                         break;
337
338                 case JAVA_WIDE:
339                         iswide = true;
340                         nextp = p + 1;
341                         break;
342
343                 case JAVA_LOOKUPSWITCH:
344                         nextp = ALIGN((p + 1), 4) + 4;
345                         nextp += code_get_u4(nextp,m) * 8 + 4;
346                         break;
347
348                 case JAVA_TABLESWITCH:
349                         nextp = ALIGN((p + 1), 4) + 4;
350                         nextp += (code_get_u4(nextp+4,m) - code_get_u4(nextp,m) + 1) * 4 + 4;
351                         break;
352                 }
353
354                 /* detect readonly variables in inlined methods */
355                 
356                 if (isnotrootlevel) { 
357                         bool iswide = oldiswide;
358                         
359                         switch (opcode) {
360                         case JAVA_ISTORE:
361                         case JAVA_LSTORE:
362                         case JAVA_FSTORE:
363                         case JAVA_DSTORE:
364                         case JAVA_ASTORE: 
365                                 if (!iswide) {
366                                         i = code_get_u1(p + 1,m);
367
368                                 } else {
369                                         i = code_get_u2(p + 1,m);
370                                 }
371                                 readonly[i] = false;
372                                 break;
373
374                         case JAVA_ISTORE_0:
375                         case JAVA_LSTORE_0:
376                         case JAVA_FSTORE_0:
377                         case JAVA_ASTORE_0:
378                                 readonly[0] = false;
379                                 break;
380
381                         case JAVA_ISTORE_1:
382                         case JAVA_LSTORE_1:
383                         case JAVA_FSTORE_1:
384                         case JAVA_ASTORE_1:
385                                 readonly[1] = false;
386                                 break;
387
388                         case JAVA_ISTORE_2:
389                         case JAVA_LSTORE_2:
390                         case JAVA_FSTORE_2:
391                         case JAVA_ASTORE_2:
392                                 readonly[2] = false;
393                                 break;
394
395                         case JAVA_ISTORE_3:
396                         case JAVA_LSTORE_3:
397                         case JAVA_FSTORE_3:
398                         case JAVA_ASTORE_3:
399                                 readonly[3] = false;
400                                 break;
401
402                         case JAVA_IINC:
403                                 if (!iswide) {
404                                         i = code_get_u1(p + 1,m);
405
406                                 } else {
407                                         i = code_get_u2(p + 1,m);
408                                 }
409                                 readonly[i] = false;
410                                 break;
411                         }
412                 }
413
414                 /*              for (i=lastlabel; i<=p; i++) label_index[i] = gp; 
415                 //              printf("lastlabel=%d p=%d gp=%d\n",lastlabel, p, gp);
416                 lastlabel = p+1; */
417                 for (i = p; i < nextp; i++) label_index[i] = gp;
418
419                 if (isnotleaflevel) { 
420
421                         switch (opcode) {
422                         case JAVA_INVOKEVIRTUAL:
423                                 if (!inlinevirtuals)
424                                         break;
425                         case JAVA_INVOKESTATIC:
426                                 i = code_get_u2(p + 1,m);
427                                 {
428                                         constant_FMIref *imr;
429                                         methodinfo *imi;
430
431                                         imr = class_getconstant(m->class, i, CONSTANT_Methodref);
432
433                                         if (!class_load(imr->class))
434                                                 return NULL;
435
436                                         if (!class_link(imr->class))
437                                                 return NULL;
438
439                                         imi = class_resolveclassmethod(imr->class,
440                                                                                                    imr->name,
441                                                                                                    imr->descriptor,
442                                                                                                    m->class,
443                                                                                                    true);
444
445                                         if (!imi)
446                                                 panic("Exception thrown while parsing bytecode"); /* XXX should be passed on */
447
448                                         if (opcode == JAVA_INVOKEVIRTUAL) {
449                                                 if (!is_unique_method(imi->class, imi, imr->name, imr->descriptor))
450                                                         break;
451                                         }
452
453                                         if (imi->flags & ACC_NATIVE) log_text("Native method,no inlining"); //DEBUG
454                                         if ((inline_env->cummethods < INLINING_MAXMETHODS) &&
455                                                 (!(imi->flags & ACC_NATIVE)) &&  
456                                                 (!inlineoutsiders || (m->class == imr->class)) && 
457                                                 (imi->jcodelength < INLINING_MAXCODESIZE) && 
458                                                 (imi->jcodelength > 0) && 
459                                                 (!inlineexceptions || (imi->exceptiontablelength == 0))) { //FIXME: eliminate empty methods?
460                                                 inlining_methodinfo *tmp;
461                                                 descriptor2types(imi);
462
463                                                 inline_env->cummethods++;
464
465                                                 if (verbose) {
466                                                         char logtext[MAXLOGTEXT];
467                                                         sprintf(logtext, "Going to inline: ");
468                                                         utf_sprint(logtext  +strlen(logtext), imi->class->name);
469                                                         strcpy(logtext + strlen(logtext), ".");
470                                                         utf_sprint(logtext + strlen(logtext), imi->name);
471                                                         utf_sprint(logtext + strlen(logtext), imi->descriptor);
472                                                         log_text(logtext);
473                                                 }
474                                                 
475                                                 tmp =inlining_analyse_method(imi, level + 1, gp, firstlocal + m->maxlocals, maxstackdepth + m->maxstack, inline_env);
476                                                 list_addlast(newnode->inlinedmethods, tmp);
477                                                 gp = tmp->stopgp;
478                                                 p = nextp;
479                                         }
480                                 }
481                                 break;
482                         }
483                 }  
484         } /* for */
485         
486         newnode->stopgp = gp;
487
488         if (DEBUGi==true) {
489           printf ("\nResult of inlining analysis of: ");
490           IMETHINFO(m);
491           printf("was called by:\n"); fflush(stdout);
492           IMETHINFO(inline_env->method);
493           printf ("label_index[0..%d]->", jcodelength);
494           for (i=0;i<jcodelength; i++) printf ("%d:%d ", i, label_index[i]);
495           printf("stopgp : %d\n",newnode->stopgp); 
496           }
497
498     return newnode;
499 }
500
501 /* --------------------------------------------------------------------*/
502 /*  print_ functions: check inline structures contain what is expected */
503 /* --------------------------------------------------------------------*/
504 void print_t_inlining_globals (t_inlining_globals *g) 
505 {
506 printf("\n------------\nt_inlining_globals struct for: \n\t");fflush(stdout); 
507 METHINFO(g->method);
508 printf("\tclass=");fflush(stdout);
509   utf_display(g->class->name);printf("\n");fflush(stdout);
510
511 printf("\tjcodelength=%i; jcode=%p;\n",g->jcodelength, g->jcode);
512
513 if (g->isinlinedmethod==true) {
514   printf("\tisinlinedmethod=true ");fflush(stdout);  
515   }
516 else {
517   printf("\tisinlinedmethod=false");fflush(stdout);  
518   }
519
520 printf("\tcumjcodelength=%i ,cummaxstack=%i ,cumextablelength=%i ",
521  g->cumjcodelength,    g->cummaxstack,  g->cumextablelength);fflush(stdout);
522 printf("\tcumlocals=%i ,cummethods=%i \n",
523  g->cumlocals,    g->cummethods);fflush(stdout);  
524
525 printf("s>s>s> ");fflush(stdout);
526 print_inlining_stack     (g->inlining_stack);
527 printf("i>i>i> "); fflush(stdout);
528 print_inlining_methodinfo(g->inlining_rootinfo);
529 printf("-------------------\n");fflush(stdout);
530 }
531
532 /* --------------------------------------------------------------------*/
533 void print_inlining_stack     ( list                *s)
534 {
535 if (s==NULL) { 
536   printf("\n\tinlining_stack: NULL\n");
537   return;
538   }
539   
540   {/* print first  element to see if get into stack */
541   t_inlining_stacknode *is;
542   printf("\n\tinlining_stack: NOT NULL\n");
543
544   is=list_first(s); 
545   if (is==NULL) { 
546     printf("\n\tinlining_stack = init'd but EMPTY\n");
547     fflush(stdout);
548     return;
549     }
550   }
551
552   {
553   t_inlining_stacknode *is;
554   printf("\n\tinlining_stack: NOT NULL\n");
555
556
557   for (is=list_first(s); 
558        is!=NULL;
559        is=list_next(s,is)) {
560          printf("\n\ti>--->inlining_stack entry: \n"); fflush(stdout);
561          METHINFO(is->method);
562          printf("i=%i, p=%i, nextp=%i, opcode=%i;\n",
563                 is->i,is->p,is->nextp,is->opcode);fflush(stdout);
564          print_inlining_methodinfo(is->inlinfo);
565     } /*end for */
566   } 
567
568 }
569
570 /* --------------------------------------------------------------------*/
571 void print_inlining_methodinfo( inlining_methodinfo *r) {
572 if (r==NULL) { 
573   printf("\n\tinlining_methodinfo: NULL\n");
574   return;
575   }
576
577 if (r->method != NULL) {
578   utf_display(r->method->class->name); printf("."); fflush(stdout); \
579   method_display(r->method); fflush(stdout); \
580   }
581 else {
582   printf("method is NULL!!!!!\n");fflush(stdout);
583   }
584
585 printf("\n\tinlining_methodinfo for:"); fflush(stdout);
586 if (r->readonly==NULL) {
587   printf("\treadonly==NULL ");fflush(stdout);  
588   }
589 else {
590   int i;
591   printf("\treadonly=");fflush(stdout);  
592   for (i = 0; i < r->method->maxlocals; i++)  {
593     if (r->readonly[i] == true)
594       printf("[i]=T;");
595     else
596       printf("[i]=F;");
597     fflush(stdout);
598     } 
599   }
600
601
602 printf("\tstartgp=%i; stopgp=%i; firstlocal=%i; label_index=%p;\n",
603           r->startgp, r->stopgp, r->firstlocal, r->label_index);
604 {int i;
605 printf ("label_index[0..%d]->", r->method->jcodelength);
606 for (i=0; i<r->method->jcodelength; i++) printf ("%d:%d ", i, r->label_index[i]);
607 }
608
609 {
610 inlining_methodinfo *im;
611 for (im=list_first(r->inlinedmethods); 
612      im!=NULL;
613      im=list_next(r->inlinedmethods,im)) {
614   } 
615 }
616 }
617
618
619 /*
620  * These are local overrides for various environment variables in Emacs.
621  * Please do not remove this and leave it at the end of the file, where
622  * Emacs will automagically detect them.
623  * ---------------------------------------------------------------------
624  * Local variables:
625  * mode: c
626  * indent-tabs-mode: t
627  * c-basic-offset: 4
628  * tab-width: 4
629  * End:
630  */