Include options.h instead of main.h.
[cacao.git] / src / vm / jit / inline / inline.c
1 /* jit/inline.c - code inliner
2
3    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4    R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
5    M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
6    P. Tomsich, J. Wenninger
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 1236 2004-06-30 19:53:03Z twisti $
30
31 */
32
33
34 #include <stdio.h>
35 #include <string.h>
36 #include "global.h"
37 #include "loader.h"
38 #include "tables.h"
39 #include "options.h"
40 #include "jit/inline.h"
41 #include "jit/jit.h"
42 #include "jit/parse.h"
43 #include "toolbox/logging.h"
44 #include "toolbox/memory.h"
45
46
47 // checked functions and macros: LOADCONST code_get OP1 BUILTIN block_insert bound_check ALIGN
48
49 // replace jcodelength loops with correct number after main for loop in parse()!
50
51 static list *inlining_stack;
52 //static list *inlining_patchlist;
53 bool isinlinedmethod;
54 int cumjcodelength;         /* cumulative immediate intruction length      */
55 static int cumlocals;
56 int cummaxstack;
57 int cumextablelength;
58 static int cummethods;
59 inlining_methodinfo *inlining_rootinfo;
60
61
62 void inlining_init(methodinfo *m)
63 {
64         inlining_stack = NULL;
65         //      inlining_patchlist = NULL;
66         isinlinedmethod = 0;
67         cumjcodelength = 0;
68         cumlocals = 0;
69         cumextablelength = 0;
70         cummaxstack = 0;
71         cummethods = 0;
72
73         inlining_stack = NEW(list);
74         list_init(inlining_stack, OFFSET(t_inlining_stacknode, linkage));
75         
76         inlining_rootinfo = inlining_analyse_method(m, 0, 0, 0, 0);
77         m->maxlocals = cumlocals;
78         m->maxstack = cummaxstack;
79 }
80
81
82 void inlining_cleanup()
83 {
84         FREE(inlining_stack, t_inlining_stacknode);
85 }
86
87
88 void inlining_push_compiler_variables(methodinfo *m, int i, int p, int nextp, int opcode, inlining_methodinfo *inlinfo) 
89 {
90         t_inlining_stacknode *new = NEW(t_inlining_stacknode);
91
92         new->i = i;
93         new->p = p;
94         new->nextp = nextp;
95         new->opcode = opcode;
96         new->method = m;
97         //      new->patchlist = inlining_patchlist;
98         new->inlinfo = inlinfo;
99         
100         list_addfirst(inlining_stack, new);
101         isinlinedmethod++;
102 }
103
104
105 void inlining_pop_compiler_variables(methodinfo *m, int *i, int *p, int *nextp, int *opcode, inlining_methodinfo **inlinfo) 
106 {
107         t_inlining_stacknode *tmp = (t_inlining_stacknode *) list_first(inlining_stack);
108
109         if (!isinlinedmethod) panic("Attempting to pop from inlining stack in toplevel method!\n");
110
111         *i = tmp->i;
112         *p = tmp->p;
113         *nextp = tmp->nextp;
114         *opcode = tmp->opcode;
115         *inlinfo = tmp->inlinfo;
116
117         /* XXX TWISTI */
118 /*      method = tmp->method; */
119 /*      class = method->class; */
120 /*      jcodelength = method->jcodelength; */
121 /*      jcode = method->jcode; */
122         //      inlining_patchlist = tmp->patchlist;
123
124         list_remove(inlining_stack, tmp);
125         FREE(tmp, t_inlining_stacknode);
126         isinlinedmethod--;
127 }
128
129
130 void inlining_set_compiler_variables_fun(methodinfo *m)
131 {
132         /* XXX TWISTI */
133 /*      method = m; */
134 /*      class = m->class; */
135 /*      jcodelength = m->jcodelength; */
136 /*      jcode = m->jcode; */
137         
138         //      inlining_patchlist = DNEW(list);
139         //      list_init(inlining_patchlist, OFFSET(t_patchlistnode, linkage));
140 }
141
142
143 /*void inlining_addpatch(instruction *iptr)  
144   {
145   t_patchlistnode *patch = DNEW(t_patchlistnode);
146   patch->iptr = iptr;
147   list_addlast(inlining_patchlist, patch);
148   }*/
149
150
151 classinfo *first_occurence(classinfo* class, utf* name, utf* desc)
152 {
153         classinfo *first = class;
154         
155         for (; class->super != NULL ; class = class->super) {
156                 if (class_findmethod(class->super, name, desc) != NULL) {
157                         first = class->super;
158                 }                       
159         }
160
161         return first;
162 }
163
164
165 bool is_unique_rec(classinfo *class, methodinfo *m, utf* name, utf* desc)
166 {
167         methodinfo *tmp = class_findmethod(class, name, desc);
168         if ((tmp != NULL) && (tmp != m))
169                 return false;
170
171         for (; class != NULL; class = class->nextsub) {
172                 if ((class->sub != NULL) && !is_unique_rec(class->sub, m, name, desc)) {
173                         return false; 
174                 }
175         }
176         return true;
177 }
178
179
180 bool is_unique_method(classinfo *class, methodinfo *m, utf* name, utf* desc)
181 {
182         classinfo *firstclass;
183         
184         /*      sprintf (logtext, "First occurence of: ");
185         utf_sprint (logtext+strlen(logtext), m->class->name);
186         strcpy (logtext+strlen(logtext), ".");
187         utf_sprint (logtext+strlen(logtext), m->name);
188         utf_sprint (logtext+strlen(logtext), m->descriptor);
189         dolog (); */
190         
191         firstclass = first_occurence(class, name, desc);
192         
193         /*      sprintf (logtext, "\nis in class:");
194         utf_sprint (logtext+strlen(logtext), firstclass->name);
195         dolog (); */
196
197         if (firstclass != class) return false;
198
199         return is_unique_rec(class, m, name, desc);
200 }
201
202
203 inlining_methodinfo *inlining_analyse_method(methodinfo *m, int level, int gp, int firstlocal, int maxstackdepth)
204 {
205         inlining_methodinfo *newnode = DNEW(inlining_methodinfo);
206         u1 *jcode = m->jcode;
207         int jcodelength = m->jcodelength;
208         int p;
209         int nextp;
210         int opcode;
211         int i;
212 /*      int lastlabel = 0; */
213         bool iswide = false, oldiswide;
214         bool *readonly = NULL;
215         int  *label_index = NULL;
216         bool isnotrootlevel = (level > 0);
217         bool isnotleaflevel = (level < INLINING_MAXDEPTH);
218
219         //      if (level == 0) gp = 0;
220         /*
221         sprintf (logtext, "Performing inlining analysis of: ");
222         utf_sprint (logtext+strlen(logtext), m->class->name);
223         strcpy (logtext+strlen(logtext), ".");
224         utf_sprint (logtext+strlen(logtext), m->name);
225         utf_sprint (logtext+strlen(logtext), m->descriptor);
226         dolog (); */
227
228         if (isnotrootlevel) {
229                 newnode->readonly = readonly = DMNEW(bool, m->maxlocals); //FIXME only paramcount entrys necessary
230                 for (i = 0; i < m->maxlocals; readonly[i++] = true);
231                 isnotrootlevel = true;
232
233         } else {
234                 readonly = NULL;
235         }
236         
237         label_index = DMNEW(int, jcodelength);
238
239         newnode->inlinedmethods = DNEW(list);
240         list_init(newnode->inlinedmethods, OFFSET(inlining_methodinfo, linkage));
241
242         newnode->method = m;
243         newnode->startgp = gp;
244         newnode->readonly = readonly;
245         newnode->label_index = label_index;
246         newnode->firstlocal = firstlocal;
247         cumjcodelength += jcodelength + m->paramcount + 1 + 5;
248
249         if ((firstlocal + m->maxlocals) > cumlocals) {
250                 cumlocals = firstlocal + m->maxlocals;
251         }
252
253         if ((maxstackdepth + m->maxstack) > cummaxstack) {
254                 cummaxstack = maxstackdepth + m->maxstack;
255         }
256
257         cumextablelength += m->exceptiontablelength;
258    
259
260         for (p = 0; p < jcodelength; gp += (nextp - p), p = nextp) {
261                 opcode = code_get_u1 (p);
262                 nextp = p + jcommandsize[opcode];
263                 oldiswide = iswide;
264
265                 /* figure out nextp */
266
267                 switch (opcode) {
268                 case JAVA_ILOAD:
269                 case JAVA_LLOAD:
270                 case JAVA_FLOAD:
271                 case JAVA_DLOAD:
272                 case JAVA_ALOAD: 
273
274                 case JAVA_ISTORE:
275                 case JAVA_LSTORE:
276                 case JAVA_FSTORE:
277                 case JAVA_DSTORE:
278                 case JAVA_ASTORE: 
279
280                 case JAVA_RET:
281                         if (iswide) {
282                                 nextp = p + 3;
283                                 iswide = false;
284                         }
285                         break;
286
287                 case JAVA_IINC:
288                         if (iswide) {
289                                 nextp = p + 5;
290                                 iswide = false;
291                         }
292                         break;
293
294                 case JAVA_WIDE:
295                         iswide = true;
296                         nextp = p + 1;
297                         break;
298
299                 case JAVA_LOOKUPSWITCH:
300                         nextp = ALIGN((p + 1), 4) + 4;
301                         nextp += code_get_u4(nextp) * 8 + 4;
302                         break;
303
304                 case JAVA_TABLESWITCH:
305                         nextp = ALIGN((p + 1), 4) + 4;
306                         nextp += (code_get_u4(nextp+4) - code_get_u4(nextp) + 1) * 4 + 4;
307                         break;
308                 }
309
310                 /* detect readonly variables in inlined methods */
311                 
312                 if (isnotrootlevel) { 
313                         bool iswide = oldiswide;
314                         
315                         switch (opcode) {
316                         case JAVA_ISTORE:
317                         case JAVA_LSTORE:
318                         case JAVA_FSTORE:
319                         case JAVA_DSTORE:
320                         case JAVA_ASTORE: 
321                                 if (!iswide) {
322                                         i = code_get_u1(p + 1);
323
324                                 } else {
325                                         i = code_get_u2(p + 1);
326                                 }
327                                 readonly[i] = false;
328                                 break;
329
330                         case JAVA_ISTORE_0:
331                         case JAVA_LSTORE_0:
332                         case JAVA_FSTORE_0:
333                         case JAVA_ASTORE_0:
334                                 readonly[0] = false;
335                                 break;
336
337                         case JAVA_ISTORE_1:
338                         case JAVA_LSTORE_1:
339                         case JAVA_FSTORE_1:
340                         case JAVA_ASTORE_1:
341                                 readonly[1] = false;
342                                 break;
343
344                         case JAVA_ISTORE_2:
345                         case JAVA_LSTORE_2:
346                         case JAVA_FSTORE_2:
347                         case JAVA_ASTORE_2:
348                                 readonly[2] = false;
349                                 break;
350
351                         case JAVA_ISTORE_3:
352                         case JAVA_LSTORE_3:
353                         case JAVA_FSTORE_3:
354                         case JAVA_ASTORE_3:
355                                 readonly[3] = false;
356                                 break;
357
358                         case JAVA_IINC:
359                                 if (!iswide) {
360                                         i = code_get_u1(p + 1);
361
362                                 } else {
363                                         i = code_get_u2(p + 1);
364                                 }
365                                 readonly[i] = false;
366                                 break;
367                         }
368                 }
369
370                 /*              for (i=lastlabel; i<=p; i++) label_index[i] = gp; 
371                 //              printf("lastlabel=%d p=%d gp=%d\n",lastlabel, p, gp);
372                 lastlabel = p+1; */
373                 for (i = p; i < nextp; i++) label_index[i] = gp;
374
375                 if (isnotleaflevel) { 
376
377                         switch (opcode) {
378                         case JAVA_INVOKEVIRTUAL:
379                                 if (!inlinevirtuals)
380                                         break;
381                         case JAVA_INVOKESTATIC:
382                                 i = code_get_u2(p + 1);
383                                 {
384                                         constant_FMIref *imr;
385                                         methodinfo *imi;
386
387                                         imr = class_getconstant(m->class, i, CONSTANT_Methodref);
388
389                                         if (!class_load(imr->class))
390                                                 return NULL;
391
392                                         if (!class_link(imr->class))
393                                                 return NULL;
394
395                                         imi = class_resolveclassmethod(imr->class,
396                                                                                                    imr->name,
397                                                                                                    imr->descriptor,
398                                                                                                    m->class,
399                                                                                                    true);
400
401                                         if (!imi)
402                                                 panic("Exception thrown while parsing bytecode"); /* XXX should be passed on */
403
404                                         if (opcode == JAVA_INVOKEVIRTUAL) {
405                                                 if (!is_unique_method(imi->class, imi, imr->name, imr->descriptor))
406                                                         break;
407                                         }
408
409                                         if ((cummethods < INLINING_MAXMETHODS) &&
410                                                 (!(imi->flags & ACC_NATIVE)) &&  
411                                                 (!inlineoutsiders || (m->class == imr->class)) && 
412                                                 (imi->jcodelength < INLINING_MAXCODESIZE) && 
413                                                 (imi->jcodelength > 0) && 
414                                                 (!inlineexceptions || (imi->exceptiontablelength == 0))) { //FIXME: eliminate empty methods?
415                                                 inlining_methodinfo *tmp;
416                                                 descriptor2types(imi);
417
418                                                 cummethods++;
419
420                                                 if (verbose) {
421                                                         char logtext[MAXLOGTEXT];
422                                                         sprintf(logtext, "Going to inline: ");
423                                                         utf_sprint(logtext  +strlen(logtext), imi->class->name);
424                                                         strcpy(logtext + strlen(logtext), ".");
425                                                         utf_sprint(logtext + strlen(logtext), imi->name);
426                                                         utf_sprint(logtext + strlen(logtext), imi->descriptor);
427                                                         log_text(logtext);
428                                                 }
429                                                 
430                                                 tmp = inlining_analyse_method(imi, level + 1, gp, firstlocal + m->maxlocals, maxstackdepth + m->maxstack);
431                                                 list_addlast(newnode->inlinedmethods, tmp);
432                                                 gp = tmp->stopgp;
433                                                 p = nextp;
434                                         }
435                                 }
436                                 break;
437                         }
438                 }  
439         } /* for */
440         
441         newnode->stopgp = gp;
442
443         /*
444         sprintf (logtext, "Result of inlining analysis of: ");
445         utf_sprint (logtext+strlen(logtext), m->class->name);
446         strcpy (logtext+strlen(logtext), ".");
447         utf_sprint (logtext+strlen(logtext), m->name);
448         utf_sprint (logtext+strlen(logtext), m->descriptor);
449         dolog ();
450         sprintf (logtext, "label_index[0..%d]->", jcodelength);
451         for (i=0; i<jcodelength; i++) sprintf (logtext, "%d:%d ", i, label_index[i]);
452         sprintf(logtext,"stopgp : %d\n",newnode->stopgp); */
453
454     return newnode;
455 }
456
457
458 /*
459  * These are local overrides for various environment variables in Emacs.
460  * Please do not remove this and leave it at the end of the file, where
461  * Emacs will automagically detect them.
462  * ---------------------------------------------------------------------
463  * Local variables:
464  * mode: c
465  * indent-tabs-mode: t
466  * c-basic-offset: 4
467  * tab-width: 4
468  * End:
469  */