1 /* jit/inline.c - code inliner
3 globals moved to structure and passed as parameter
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
10 This file is part of CACAO.
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.
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.
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
27 Contact: cacao@complang.tuwien.ac.at
29 Authors: Dieter Thuernbeck
31 $Id: inline.c 1432 2004-11-03 12:14:50Z jowenn $
42 #include "jit/inline.h"
44 #include "jit/parse.h"
45 #include "toolbox/logging.h"
46 #include "toolbox/memory.h"
49 utf_display(m->class->name); printf("."); fflush(stdout); \
50 method_display(m); fflush(stdout); \
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);
61 // checked functions and macros: LOADCONST code_get OP1 BUILTIN block_insert bound_check ALIGN
63 // replace jcodelength loops with correct number after main for loop in parse()!
65 /*-----------------------------------------------------------*/
66 /* just initialize global structure for non-inlining */
67 /*-----------------------------------------------------------*/
69 t_inlining_globals *inlining_init0(methodinfo *m,
70 t_inlining_globals *inline_env)
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;
84 /*-----------------------------------------------------------*/
86 t_inlining_globals *inlining_init(methodinfo *m)
88 t_inlining_globals *inline_env = DNEW(t_inlining_globals);
89 inlining_init0(m,inline_env);
93 printf("\n-------- Inlining init for: "); fflush(stdout);
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;
112 printf("(l,s) (%i,%i) was (%i,%i)\n",
113 m->maxlocals, inline_env->cumlocals,
114 m->maxstack, inline_env->cummaxstack); fflush(stdout);
118 m->maxlocals = inline_env->cumlocals; //orig not used
119 m->maxstack = inline_env->cummaxstack; //orig global maxstack var!!
121 //panic("TEMP so can test just inline init\n");
127 void inlining_cleanup(t_inlining_globals *inline_env)
129 FREE(inline_env->inlining_stack, t_inlining_stacknode);
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)
135 t_inlining_stacknode *new = NEW(t_inlining_stacknode);
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++;
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)
158 t_inlining_stacknode *tmp
159 = (t_inlining_stacknode *) list_first(inline_env->inlining_stack);
161 if (!inline_env->isinlinedmethod) panic("Attempting to pop from inlining stack in toplevel method!\n");
166 *opcode = tmp->opcode;
168 *lineindex=tmp->lineindex;
169 *currentline=tmp->currentline;
170 *currentline=tmp->linepcchange;
172 *inlinfo = tmp->inlinfo;
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*/
179 list_remove(inline_env->inlining_stack, tmp);
180 FREE(tmp, t_inlining_stacknode);
181 inline_env->isinlinedmethod--;
185 void inlining_set_compiler_variables_fun(methodinfo *m,
186 t_inlining_globals *inline_env)
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*/
196 classinfo *first_occurence(classinfo* class, utf* name, utf* desc)
198 classinfo *first = class;
200 for (; class->super != NULL ; class = class->super) {
201 if (class_findmethod(class->super, name, desc) != NULL) {
202 first = class->super;
210 bool is_unique_rec(classinfo *class, methodinfo *m, utf* name, utf* desc)
212 methodinfo *tmp = class_findmethod(class, name, desc);
213 if ((tmp != NULL) && (tmp != m))
216 for (; class != NULL; class = class->nextsub) {
217 if ((class->sub != NULL) && !is_unique_rec(class->sub, m, name, desc)) {
225 bool is_unique_method(classinfo *class, methodinfo *m, utf* name, utf* desc)
227 classinfo *firstclass;
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);
236 firstclass = first_occurence(class, name, desc);
238 /* sprintf (logtext, "\nis in class:");
239 utf_sprint (logtext+strlen(logtext), firstclass->name);
242 if (firstclass != class) return false;
244 return is_unique_rec(class, m, name, desc);
247 inlining_methodinfo *inlining_analyse_method(methodinfo *m,
249 int firstlocal, int maxstackdepth,
250 t_inlining_globals *inline_env)
252 inlining_methodinfo *newnode = DNEW(inlining_methodinfo);
253 /*u1 *jcode = m->jcode;*/
254 int jcodelength = m->jcodelength;
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);
265 // if (level == 0) gp = 0;
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);
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;
283 label_index = DMNEW(int, jcodelength+200);
285 newnode->inlinedmethods = DNEW(list);
286 list_init(newnode->inlinedmethods, OFFSET(inlining_methodinfo, linkage));
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;
295 if ((firstlocal + m->maxlocals) > inline_env->cumlocals) {
296 inline_env->cumlocals = firstlocal + m->maxlocals;
299 if ((maxstackdepth + m->maxstack) > inline_env->cummaxstack) {
300 inline_env->cummaxstack = maxstackdepth + m->maxstack;
303 inline_env->cumextablelength += m->exceptiontablelength;
306 for (p = 0; p < jcodelength; gp += (nextp - p), p = nextp) {
307 opcode = code_get_u1 (p,m);
308 nextp = p + jcommandsize[opcode];
311 /* figure out nextp */
345 case JAVA_LOOKUPSWITCH:
346 nextp = ALIGN((p + 1), 4) + 4;
347 nextp += code_get_u4(nextp,m) * 8 + 4;
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;
356 /* detect readonly variables in inlined methods */
358 if (isnotrootlevel) {
359 bool iswide = oldiswide;
368 i = code_get_u1(p + 1,m);
371 i = code_get_u2(p + 1,m);
406 i = code_get_u1(p + 1,m);
409 i = code_get_u2(p + 1,m);
416 /* for (i=lastlabel; i<=p; i++) label_index[i] = gp;
417 // printf("lastlabel=%d p=%d gp=%d\n",lastlabel, p, gp);
419 for (i = p; i < nextp; i++) label_index[i] = gp;
421 if (isnotleaflevel) {
424 case JAVA_INVOKEVIRTUAL:
427 case JAVA_INVOKESTATIC:
428 i = code_get_u2(p + 1,m);
430 constant_FMIref *imr;
433 imr = class_getconstant(m->class, i, CONSTANT_Methodref);
435 if (!class_load(imr->class))
438 if (!class_link(imr->class))
441 imi = class_resolveclassmethod(imr->class,
448 panic("Exception thrown while parsing bytecode"); /* XXX should be passed on */
450 if (opcode == JAVA_INVOKEVIRTUAL) {
451 if (!is_unique_method(imi->class, imi, imr->name, imr->descriptor))
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);
465 inline_env->cummethods++;
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);
477 tmp =inlining_analyse_method(imi, level + 1, gp, firstlocal + m->maxlocals, maxstackdepth + m->maxstack, inline_env);
478 list_addlast(newnode->inlinedmethods, tmp);
488 newnode->stopgp = gp;
491 printf ("\nResult of inlining analysis of: ");
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);
503 /* --------------------------------------------------------------------*/
504 /* print_ functions: check inline structures contain what is expected */
505 /* --------------------------------------------------------------------*/
506 void print_t_inlining_globals (t_inlining_globals *g)
508 printf("\n------------\nt_inlining_globals struct for: \n\t");fflush(stdout);
510 printf("\tclass=");fflush(stdout);
511 utf_display(g->class->name);printf("\n");fflush(stdout);
513 printf("\tjcodelength=%i; jcode=%p;\n",g->jcodelength, g->jcode);
515 if (g->isinlinedmethod==true) {
516 printf("\tisinlinedmethod=true ");fflush(stdout);
519 printf("\tisinlinedmethod=false");fflush(stdout);
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);
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);
534 /* --------------------------------------------------------------------*/
535 void print_inlining_stack ( list *s)
538 printf("\n\tinlining_stack: NULL\n");
542 {/* print first element to see if get into stack */
543 t_inlining_stacknode *is;
544 printf("\n\tinlining_stack: NOT NULL\n");
548 printf("\n\tinlining_stack = init'd but EMPTY\n");
555 t_inlining_stacknode *is;
556 printf("\n\tinlining_stack: NOT NULL\n");
559 for (is=list_first(s);
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);
572 /* --------------------------------------------------------------------*/
573 void print_inlining_methodinfo( inlining_methodinfo *r) {
575 printf("\n\tinlining_methodinfo: NULL\n");
579 if (r->method != NULL) {
580 utf_display(r->method->class->name); printf("."); fflush(stdout); \
581 method_display(r->method); fflush(stdout); \
584 printf("method is NULL!!!!!\n");fflush(stdout);
587 printf("\n\tinlining_methodinfo for:"); fflush(stdout);
588 if (r->readonly==NULL) {
589 printf("\treadonly==NULL ");fflush(stdout);
593 printf("\treadonly=");fflush(stdout);
594 for (i = 0; i < r->method->maxlocals; i++) {
595 if (r->readonly[i] == true)
604 printf("\tstartgp=%i; stopgp=%i; firstlocal=%i; label_index=%p;\n",
605 r->startgp, r->stopgp, r->firstlocal, r->label_index);
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]);
612 inlining_methodinfo *im;
613 for (im=list_first(r->inlinedmethods);
615 im=list_next(r->inlinedmethods,im)) {
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 * ---------------------------------------------------------------------
628 * indent-tabs-mode: t