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