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