1 /* jit/codegen.inc - architecture independent code generator
3 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4 Institut f. Computersprachen, TU Wien
5 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Probst,
6 S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich,
9 This file is part of CACAO.
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2, or (at
14 your option) any later version.
16 This program is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
26 Contact: cacao@complang.tuwien.ac.at
28 Authors: Reinhard Grafl
31 Changes: Michael Gschwind
34 All functions assume the following code area / data area layout:
38 | code area | code area grows to higher addresses
40 +-----------+ <-- start of procedure
42 | data area | data area grows to lower addresses
46 The functions first write into a temporary code/data area allocated by
47 "codegen_init". "codegen_finish" copies the code and data area into permanent
48 memory. All functions writing values into the data area return the offset
49 relative the begin of the code area (start of procedure).
51 $Id: codegen.inc 1259 2004-06-30 21:35:45Z twisti $
58 #include "statistics.h"
59 #include "toolbox/memory.h"
60 #include "toolbox/logging.h"
61 #include "toolbox/avl.h"
62 #include "threads/thread.h"
65 /************************* critical sections *********************************/
67 struct threadcritnodetemp {
68 struct threadcritnodetemp *next;
69 int mcodebegin, mcodeend, mcoderestart;
72 #define MCODEINITSIZE (1<<15) /* 32 Kbyte code area initialization size */
73 #define DSEGINITSIZE (1<<12) /* 4 Kbyte data area initialization size */
75 static u1* mcodebase = NULL; /* base pointer of code area */
76 static s4* mcodeend = NULL; /* pointer to end of code area */
77 static int mcodesize; /* complete size of code area (bytes) */
79 static u1* dsegtop = NULL; /* pointer to top (end) of data area */
80 static int dsegsize; /* complete size of data area (bytes) */
81 int dseglen; /* used size of data area (bytes) */
82 /* data area grows from top to bottom */
84 static jumpref *jumpreferences; /* list of jumptable target addresses */
85 static dataref *datareferences; /* list of data segment references */
86 static branchref *xboundrefs; /* list of bound check branches */
87 static branchref *xcheckarefs; /* list of array size check branches */
88 static branchref *xnullrefs; /* list of null check branches */
89 static branchref *xcastrefs; /* list of cast check branches */
90 static branchref *xdivrefs; /* list of divide by zero branches */
91 static branchref *xexceptionrefs; /* list of exception branches */
92 static linenumberref *linenumberreferences; /*list of line numbers and the program counters of their first instruction*/
93 static s4 linenumbertablesizepos;
94 static s4 linenumbertablestartpos;
95 static s4 linenumbertab;
97 static struct threadcritnodetemp *threadcrit;
98 /* List of critical code regions */
99 static struct threadcritnodetemp threadcritcurrent;
100 static int threadcritcount; /* Number of critical regions */
102 int parentargs_base; /* offset in stackframe for the parameter from the caller*/
104 void codegen_init(); /* allocates code and data area */
105 void codegen_close(); /* releases temporary storage */
106 static void codegen_finish(); /* makes code and data area permanent and */
107 /* updates branch references to code/data */
109 static s4 dseg_adds4(s4 value); /* adds an int to data area */
111 #if !defined(__I386__)
112 static s4 dseg_adds8(s8 value); /* adds an long to data area */
115 static s4 dseg_addfloat (float value); /* adds an float to data area */
116 static s4 dseg_adddouble(double value); /* adds an double to data area */
119 #define dseg_addaddress(value) dseg_adds8((s8)(value))
121 #define dseg_addaddress(value) dseg_adds4((s4)(value))
124 static void dseg_addtarget(basicblock *target);
125 static void dseg_adddata(u1 *ptr);
126 static void codegen_addreference(basicblock *target, void *branchptr);
127 static void codegen_addxboundrefs(void *branchptr, s4 reg);
128 static void codegen_addxnullrefs(void *branchptr);
129 static void codegen_addxcastrefs(void *branchptr);
130 static void codegen_addxdivrefs(void *branchptr);
131 static void codegen_addxexceptionrefs(void *branchptr);
132 static void codegen_threadcritrestart(int offset);
133 static void codegen_threadcritstart(int offset);
134 static void codegen_threadcritstop(int offset);
136 #if defined(__I386__) || defined(__X86_64__)
137 typedef struct _methodtree_element methodtree_element;
139 struct _methodtree_element {
144 static struct avl_table *methodtree=0;
145 static int methodtree_comparator(const void *pc, const void *element,
149 void dseg_display(s4 *s4ptr);
153 /* codegen_init allocates and initialises code area, data area and references */
158 mcodebase = MNEW(u1, MCODEINITSIZE);
159 mcodesize = MCODEINITSIZE;
163 dsegtop = MNEW(u1, DSEGINITSIZE);
164 dsegsize = DSEGINITSIZE;
170 linenumberreferences = NULL;
171 linenumbertablesizepos = 0;
172 linenumbertablestartpos = 0;
174 jumpreferences = NULL;
175 datareferences = NULL;
181 xexceptionrefs = NULL;
183 #if defined(__I386__) || defined(__X86_64__)
185 methodtree_element *mte;
187 methodtree = avl_create(methodtree_comparator, NULL, NULL);
189 mte = NEW(methodtree_element);
191 mte->startpc = asm_calljavafunction;
192 mte->endpc = asm_calljavafunction2 - 1;
194 avl_insert(methodtree, mte);
196 mte = NEW(methodtree_element);
198 mte->startpc = asm_calljavafunction2;
199 mte->endpc = asm_call_jit_compiler - 1;
201 avl_insert(methodtree, mte);
205 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
206 threadcritcurrent.next = NULL;
213 /* codegen_close releases temporary code and data area */
218 MFREE(mcodebase, u1, mcodesize);
223 MFREE(dsegtop - dsegsize, u1, dsegsize);
230 /* codegen_increase doubles code area */
232 static s4 *codegen_increase(u1 *codeptr)
236 len = codeptr - mcodebase;
237 mcodebase = MREALLOC(mcodebase, u1, mcodesize, mcodesize * 2);
239 mcodeend = (s4*) (mcodebase + mcodesize);
240 return (s4*) (mcodebase + len);
245 /* desg_increase doubles data area */
247 static void dseg_increase()
249 u1 *newstorage = MNEW(u1, dsegsize * 2);
250 memcpy(newstorage + dsegsize, dsegtop - dsegsize, dsegsize);
251 MFREE(dsegtop - dsegsize, u1, dsegsize);
252 dsegtop = newstorage;
259 static s4 dseg_adds4_increase(s4 value)
262 *((s4 *) (dsegtop - dseglen)) = value;
268 static s4 dseg_adds4(s4 value)
273 dataptr = (s4 *) (dsegtop - dseglen);
274 if (dseglen > dsegsize)
275 return dseg_adds4_increase(value);
282 #if !defined(__I386__)
283 static s4 dseg_adds8_increase(s8 value)
286 *((s8 *) (dsegtop - dseglen)) = value;
291 static s4 dseg_adds8(s8 value)
295 dseglen = ALIGN (dseglen + 8, 8);
296 dataptr = (s8 *) (dsegtop - dseglen);
297 if (dseglen > dsegsize)
298 return dseg_adds8_increase(value);
305 static s4 dseg_addfloat_increase(float value)
308 *((float *) (dsegtop - dseglen)) = value;
314 static s4 dseg_addfloat(float value)
319 dataptr = (float *) (dsegtop - dseglen);
320 if (dseglen > dsegsize)
321 return dseg_addfloat_increase(value);
328 static s4 dseg_adddouble_increase(double value)
331 *((double *) (dsegtop - dseglen)) = value;
337 static s4 dseg_adddouble(double value)
341 dseglen = ALIGN (dseglen + 8, 8);
342 dataptr = (double *) (dsegtop - dseglen);
343 if (dseglen > dsegsize)
344 return dseg_adddouble_increase(value);
351 static void dseg_addtarget(basicblock *target)
353 jumpref *jr = DNEW(jumpref);
355 jr->tablepos = dseg_addaddress(NULL);
357 jr->next = jumpreferences;
363 static void dseg_adddata(u1 *ptr)
365 dataref *dr = DNEW(dataref);
367 dr->pos = (u1 *) (ptr - mcodebase);
368 dr->next = datareferences;
372 static void dseg_addlinenumbertablesize() {
374 dseg_adds4(0); /*PADDING*/
376 linenumbertablesizepos=dseg_addaddress(NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
378 linenumbertablestartpos=dseg_addaddress(NULL);
380 dseg_adds4(0); /*PADDING*/
384 static void dseg_addlinenumber(u2 linenumber,u1 *ptr) {
385 linenumberref *lr=DNEW(linenumberref);
386 lr->linenumber=linenumber;
388 lr->targetmpc=(ptr-mcodebase);
389 lr->next=linenumberreferences;
390 linenumberreferences=lr;
393 static void codegen_addreference(basicblock *target, void *branchptr)
395 s4 branchpos = (u1*) branchptr - mcodebase;
397 if (target->mpc >= 0) {
398 gen_resolvebranch((u1*) mcodebase + branchpos, branchpos, target->mpc);
401 branchref *br = DNEW(branchref);
403 br->branchpos = branchpos;
404 br->next = target->branchrefs;
405 target->branchrefs= br;
411 static void codegen_addxboundrefs(void *branchptr, s4 reg)
413 s4 branchpos = (u1*) branchptr - mcodebase;
415 branchref *br = DNEW(branchref);
417 br->branchpos = branchpos;
419 br->next = xboundrefs;
425 static void codegen_addxcheckarefs(void *branchptr)
427 s4 branchpos = (u1*) branchptr - mcodebase;
429 branchref *br = DNEW(branchref);
431 br->branchpos = branchpos;
432 br->next = xcheckarefs;
438 static void codegen_addxnullrefs(void *branchptr)
440 s4 branchpos = (u1*) branchptr - mcodebase;
442 branchref *br = DNEW(branchref);
444 br->branchpos = branchpos;
445 br->next = xnullrefs;
451 static void codegen_addxcastrefs(void *branchptr)
453 s4 branchpos = (u1*) branchptr - mcodebase;
455 branchref *br = DNEW(branchref);
457 br->branchpos = branchpos;
458 br->next = xcastrefs;
463 static void codegen_addxexceptionrefs(void *branchptr)
465 s4 branchpos = (u1*) branchptr - mcodebase;
467 branchref *br = DNEW(branchref);
469 br->branchpos = branchpos;
470 br->next = xexceptionrefs;
475 static void codegen_addxdivrefs(void *branchptr)
477 s4 branchpos = (u1*) branchptr - mcodebase;
479 branchref *br = DNEW(branchref);
481 br->branchpos = branchpos;
487 static void codegen_createlinenumbertable() {
489 /*log_text("codegen_createlinnumbertable");*/
492 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
493 /*log_text("Adding line number entry");*/
494 lr->tablepos=dseg_addaddress(NULL);
495 if (linenumbertab==0) linenumbertab=lr->tablepos;
496 dseg_addaddress(lr->linenumber);
503 #if defined(__I386__) || defined(__X86_64__)
504 static int methodtree_comparator(const void *pc, const void *element,
507 methodtree_element *mte;
508 methodtree_element *mtepc;
510 mte = (methodtree_element *) element;
511 mtepc = (methodtree_element *) pc;
513 /* compare both startpc and endpc of pc, even if they have the same value,
514 otherwise the avl_probe sometime thinks the element is still in the
516 if (mte->startpc <= mtepc->startpc && mtepc->startpc <= mte->endpc &&
517 mte->startpc <= mtepc->endpc && mtepc->endpc <= mte->endpc) {
520 } else if (mtepc->startpc < mte->startpc) {
530 void *codegen_findmethod1(void *pc)
532 void * retVal=findmethod(pc);
533 methodinfo **ma=(methodinfo**)retVal;
534 methodinfo *m=ma[-1];
537 utf_display(m->name);
540 else log_text("No methodinfo");
545 void *codegen_findmethod(void *pc)
547 methodtree_element *mtepc;
548 methodtree_element *mte;
550 mtepc = NEW(methodtree_element);
554 mte = avl_find(methodtree, mtepc);
556 FREE(mtepc, methodtree_element);
559 throw_cacao_exception_exit(string_java_lang_InternalError, "cannot find function");
566 static void codegen_finish(methodinfo *m, int mcodelen)
573 /* printf("codegen_finish\n"); */
574 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
575 extralen += sizeof(threadcritnode) * threadcritcount;
578 #if defined(STATISTICS)
580 count_code_len += mcodelen;
581 count_data_len += dseglen;
585 dseglen = ALIGN(dseglen, MAX_ALIGN);
586 alignedlen = ALIGN(mcodelen, MAX_ALIGN) + dseglen;
588 m->mcodelength = mcodelen + dseglen;
589 m->mcode = CNEW(u1, alignedlen + extralen);
591 memcpy(m->mcode, dsegtop - dseglen, dseglen);
592 memcpy(m->mcode + dseglen, mcodebase, mcodelen);
594 m->entrypoint = epoint = (u1 *) (m->mcode + dseglen);
596 /* jump table resolving */
599 *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
604 /* line number table resolving */
613 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
615 *((void**)(epoint+lr->tablepos))=epoint+lr->targetmpc;
616 /*log_text("resolving line number information");*/
619 *((void**)(epoint+linenumbertablestartpos))=epoint+linenumbertab;
621 *((s8*)(epoint+linenumbertablesizepos))=lrtlen;
623 *((s4*)(epoint+linenumbertablesizepos))=lrtlen;
628 #if defined(__I386__) || defined(__X86_64__)
632 /* add method into methodtree to find the entrypoint */
633 methodtree_element *mte;
635 mte = NEW(methodtree_element);
636 mte->startpc = m->entrypoint;
637 mte->endpc = m->entrypoint + mcodelen;
639 if (avl_insert(methodtree, mte))
640 panic("duplicate entry");
642 /* data segment references resolving */
645 *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
652 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
654 threadcritnode *n = (threadcritnode*) (m->mcode + alignedlen);
656 struct threadcritnodetemp *nt = threadcrit;
658 for (i=0; i<threadcritcount; i++)
660 n->mcodebegin = m->mcode + nt->mcodebegin;
661 n->mcodeend = m->mcode + nt->mcodeend;
662 n->mcoderestart = m->mcode + nt->mcoderestart;
663 thread_registercritical(n);
672 #if defined(__I386__) || defined(__X86_64__)
673 void codegen_insertNative(void *startpc, void *endpc)
675 methodtree_element *mte;
678 methodtree_element *mte;
680 methodtree = avl_create(methodtree_comparator, NULL, NULL);
682 mte = NEW(methodtree_element);
683 mte->startpc = asm_calljavafunction;
684 mte->endpc = asm_calljavafunction2 - 1;
685 avl_insert(methodtree, mte);
687 mte = NEW(methodtree_element);
688 mte->startpc = asm_calljavafunction2;
689 mte->endpc = asm_call_jit_compiler - 1;
690 avl_insert(methodtree, mte);
693 mte = NEW(methodtree_element);
694 mte->startpc = startpc;
697 if (avl_insert(methodtree, mte))
698 panic("duplicate entry");
703 void dseg_display(s4 *s4ptr)
707 printf(" --- dump of datasegment\n");
708 for (i = dseglen; i > 0 ; i -= 4) {
709 printf("-%6x: %8x\n", i, (int)(*s4ptr++));
711 printf(" --- begin of data segment: %p\n", s4ptr);
716 This function determines a register, to which the result of an operation
717 should go, when it is ultimatively intended to store the result in
719 If v is assigned to an actual register, this register will be returned.
720 Otherwise (when v is spilled) this function returns tempregnum.
721 If not already done, regoff and flags are set in the stack location.
724 static int reg_of_var(methodinfo *m, stackptr v, int tempregnum)
728 switch (v->varkind) {
730 if (!(v->flags & INMEMORY))
734 var = &(m->registerdata->interfaces[v->varnum][v->type]);
735 v->regoff = var->regoff;
736 if (!(var->flags & INMEMORY))
740 var = &(m->registerdata->locals[v->varnum][v->type]);
741 v->regoff = var->regoff;
742 if (!(var->flags & INMEMORY))
746 v->regoff = v->varnum;
747 if (IS_FLT_DBL_TYPE(v->type)) {
748 if (v->varnum < m->registerdata->fltreg_argnum) {
749 v->regoff = m->registerdata->argfltregs[v->varnum];
750 return(m->registerdata->argfltregs[v->varnum]);
754 if (v->varnum < m->registerdata->intreg_argnum) {
755 v->regoff = m->registerdata->argintregs[v->varnum];
756 return(m->registerdata->argintregs[v->varnum]);
758 v->regoff -= m->registerdata->intreg_argnum;
761 v->flags |= INMEMORY;
766 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
767 void codegen_threadcritrestart(int offset)
769 threadcritcurrent.mcoderestart = offset;
772 void codegen_threadcritstart(int offset)
774 threadcritcurrent.mcodebegin = offset;
777 void codegen_threadcritstop(int offset)
779 threadcritcurrent.next = threadcrit;
780 threadcritcurrent.mcodeend = offset;
781 threadcrit = DNEW(struct threadcritnodetemp);
782 *threadcrit = threadcritcurrent;
788 * These are local overrides for various environment variables in Emacs.
789 * Please do not remove this and leave it at the end of the file, where
790 * Emacs will automagically detect them.
791 * ---------------------------------------------------------------------
794 * indent-tabs-mode: t