1 /* jit/inline.c - code inliner
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
8 This file is part of CACAO.
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.
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.
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
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Dieter Thuernbeck
29 $Id: inline.c 1236 2004-06-30 19:53:03Z twisti $
40 #include "jit/inline.h"
42 #include "jit/parse.h"
43 #include "toolbox/logging.h"
44 #include "toolbox/memory.h"
47 // checked functions and macros: LOADCONST code_get OP1 BUILTIN block_insert bound_check ALIGN
49 // replace jcodelength loops with correct number after main for loop in parse()!
51 static list *inlining_stack;
52 //static list *inlining_patchlist;
54 int cumjcodelength; /* cumulative immediate intruction length */
58 static int cummethods;
59 inlining_methodinfo *inlining_rootinfo;
62 void inlining_init(methodinfo *m)
64 inlining_stack = NULL;
65 // inlining_patchlist = NULL;
73 inlining_stack = NEW(list);
74 list_init(inlining_stack, OFFSET(t_inlining_stacknode, linkage));
76 inlining_rootinfo = inlining_analyse_method(m, 0, 0, 0, 0);
77 m->maxlocals = cumlocals;
78 m->maxstack = cummaxstack;
82 void inlining_cleanup()
84 FREE(inlining_stack, t_inlining_stacknode);
88 void inlining_push_compiler_variables(methodinfo *m, int i, int p, int nextp, int opcode, inlining_methodinfo *inlinfo)
90 t_inlining_stacknode *new = NEW(t_inlining_stacknode);
97 // new->patchlist = inlining_patchlist;
98 new->inlinfo = inlinfo;
100 list_addfirst(inlining_stack, new);
105 void inlining_pop_compiler_variables(methodinfo *m, int *i, int *p, int *nextp, int *opcode, inlining_methodinfo **inlinfo)
107 t_inlining_stacknode *tmp = (t_inlining_stacknode *) list_first(inlining_stack);
109 if (!isinlinedmethod) panic("Attempting to pop from inlining stack in toplevel method!\n");
114 *opcode = tmp->opcode;
115 *inlinfo = tmp->inlinfo;
118 /* method = tmp->method; */
119 /* class = method->class; */
120 /* jcodelength = method->jcodelength; */
121 /* jcode = method->jcode; */
122 // inlining_patchlist = tmp->patchlist;
124 list_remove(inlining_stack, tmp);
125 FREE(tmp, t_inlining_stacknode);
130 void inlining_set_compiler_variables_fun(methodinfo *m)
134 /* class = m->class; */
135 /* jcodelength = m->jcodelength; */
136 /* jcode = m->jcode; */
138 // inlining_patchlist = DNEW(list);
139 // list_init(inlining_patchlist, OFFSET(t_patchlistnode, linkage));
143 /*void inlining_addpatch(instruction *iptr)
145 t_patchlistnode *patch = DNEW(t_patchlistnode);
147 list_addlast(inlining_patchlist, patch);
151 classinfo *first_occurence(classinfo* class, utf* name, utf* desc)
153 classinfo *first = class;
155 for (; class->super != NULL ; class = class->super) {
156 if (class_findmethod(class->super, name, desc) != NULL) {
157 first = class->super;
165 bool is_unique_rec(classinfo *class, methodinfo *m, utf* name, utf* desc)
167 methodinfo *tmp = class_findmethod(class, name, desc);
168 if ((tmp != NULL) && (tmp != m))
171 for (; class != NULL; class = class->nextsub) {
172 if ((class->sub != NULL) && !is_unique_rec(class->sub, m, name, desc)) {
180 bool is_unique_method(classinfo *class, methodinfo *m, utf* name, utf* desc)
182 classinfo *firstclass;
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);
191 firstclass = first_occurence(class, name, desc);
193 /* sprintf (logtext, "\nis in class:");
194 utf_sprint (logtext+strlen(logtext), firstclass->name);
197 if (firstclass != class) return false;
199 return is_unique_rec(class, m, name, desc);
203 inlining_methodinfo *inlining_analyse_method(methodinfo *m, int level, int gp, int firstlocal, int maxstackdepth)
205 inlining_methodinfo *newnode = DNEW(inlining_methodinfo);
206 u1 *jcode = m->jcode;
207 int jcodelength = m->jcodelength;
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);
219 // if (level == 0) gp = 0;
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);
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;
237 label_index = DMNEW(int, jcodelength);
239 newnode->inlinedmethods = DNEW(list);
240 list_init(newnode->inlinedmethods, OFFSET(inlining_methodinfo, linkage));
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;
249 if ((firstlocal + m->maxlocals) > cumlocals) {
250 cumlocals = firstlocal + m->maxlocals;
253 if ((maxstackdepth + m->maxstack) > cummaxstack) {
254 cummaxstack = maxstackdepth + m->maxstack;
257 cumextablelength += m->exceptiontablelength;
260 for (p = 0; p < jcodelength; gp += (nextp - p), p = nextp) {
261 opcode = code_get_u1 (p);
262 nextp = p + jcommandsize[opcode];
265 /* figure out nextp */
299 case JAVA_LOOKUPSWITCH:
300 nextp = ALIGN((p + 1), 4) + 4;
301 nextp += code_get_u4(nextp) * 8 + 4;
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;
310 /* detect readonly variables in inlined methods */
312 if (isnotrootlevel) {
313 bool iswide = oldiswide;
322 i = code_get_u1(p + 1);
325 i = code_get_u2(p + 1);
360 i = code_get_u1(p + 1);
363 i = code_get_u2(p + 1);
370 /* for (i=lastlabel; i<=p; i++) label_index[i] = gp;
371 // printf("lastlabel=%d p=%d gp=%d\n",lastlabel, p, gp);
373 for (i = p; i < nextp; i++) label_index[i] = gp;
375 if (isnotleaflevel) {
378 case JAVA_INVOKEVIRTUAL:
381 case JAVA_INVOKESTATIC:
382 i = code_get_u2(p + 1);
384 constant_FMIref *imr;
387 imr = class_getconstant(m->class, i, CONSTANT_Methodref);
389 if (!class_load(imr->class))
392 if (!class_link(imr->class))
395 imi = class_resolveclassmethod(imr->class,
402 panic("Exception thrown while parsing bytecode"); /* XXX should be passed on */
404 if (opcode == JAVA_INVOKEVIRTUAL) {
405 if (!is_unique_method(imi->class, imi, imr->name, imr->descriptor))
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);
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);
430 tmp = inlining_analyse_method(imi, level + 1, gp, firstlocal + m->maxlocals, maxstackdepth + m->maxstack);
431 list_addlast(newnode->inlinedmethods, tmp);
441 newnode->stopgp = gp;
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);
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); */
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 * ---------------------------------------------------------------------
465 * indent-tabs-mode: t