1 /* src/vm/jit/codegen-common.c - architecture independent code generator stuff
3 Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
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., 51 Franklin Street, Fifth Floor, Boston, MA
25 All functions assume the following code area / data area layout:
29 | code area | code area grows to higher addresses
31 +-----------+ <-- start of procedure
33 | data area | data area grows to lower addresses
37 The functions first write into a temporary code/data area allocated by
38 "codegen_init". "codegen_finish" copies the code and data area into permanent
39 memory. All functions writing values into the data area return the offset
40 relative the begin of the code area (start of procedure).
42 $Id: codegen-common.c 7489 2007-03-08 17:12:56Z michi $
54 #if defined(ENABLE_JIT)
55 /* this is required PATCHER_CALL_SIZE */
60 /* this is required for REG_SPLIT */
64 #include "mm/memory.h"
66 #include "toolbox/avl.h"
67 #include "toolbox/list.h"
68 #include "toolbox/logging.h"
70 #include "native/jni.h"
71 #include "native/native.h"
73 #if defined(ENABLE_THREADS)
74 # include "threads/native/threads.h"
77 #include "vm/exceptions.h"
78 #include "vm/stringlocal.h"
80 #include "vm/jit/abi.h"
81 #include "vm/jit/asmpart.h"
82 #include "vm/jit/codegen-common.h"
84 #if defined(ENABLE_DISASSEMBLER)
85 # include "vm/jit/disass.h"
88 #include "vm/jit/dseg.h"
89 #include "vm/jit/jit.h"
90 #include "vm/jit/md.h"
91 #include "vm/jit/replace.h"
92 #include "vm/jit/stacktrace.h"
94 #if defined(ENABLE_INTRP)
95 #include "vm/jit/intrp/intrp.h"
98 #include "vmcore/method.h"
99 #include "vmcore/options.h"
101 #if defined(ENABLE_STATISTICS)
102 # include "vmcore/statistics.h"
106 /* in this tree we store all method addresses *********************************/
108 static avl_tree *methodtree = NULL;
109 static s4 methodtree_comparator(const void *pc, const void *element);
112 /* codegen_init ****************************************************************
116 *******************************************************************************/
118 void codegen_init(void)
120 /* this tree is global, not method specific */
123 #if defined(ENABLE_JIT)
124 methodtree_element *mte;
127 methodtree = avl_create(&methodtree_comparator);
129 #if defined(ENABLE_JIT)
130 /* insert asm_vm_call_method */
132 mte = NEW(methodtree_element);
134 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
135 mte->endpc = (u1 *) ((ptrint) asm_call_jit_compiler - 1);
137 avl_insert(methodtree, mte);
138 #endif /* defined(ENABLE_JIT) */
143 /* codegen_setup ***************************************************************
145 Allocates and initialises code area, data area and references.
147 *******************************************************************************/
149 void codegen_setup(jitdata *jd)
154 /* get required compiler data */
159 cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
160 cd->mcodeend = cd->mcodebase + MCODEINITSIZE;
161 cd->mcodesize = MCODEINITSIZE;
163 /* initialize mcode variables */
165 cd->mcodeptr = cd->mcodebase;
166 cd->lastmcodeptr = cd->mcodebase;
168 #if defined(ENABLE_INTRP)
169 /* native dynamic superinstructions variables */
172 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
173 cd->ncodesize = NCODEINITSIZE;
175 /* initialize ncode variables */
177 cd->ncodeptr = cd->ncodebase;
179 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
180 cd->superstarts = NULL;
187 cd->jumpreferences = NULL;
189 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
190 cd->datareferences = NULL;
193 cd->exceptionrefs = NULL;
194 /* cd->patchrefs = list_create_dump(OFFSET(patchref, linkage)); */
195 cd->patchrefs = NULL;
197 cd->linenumberreferences = NULL;
198 cd->linenumbertablesizepos = 0;
199 cd->linenumbertablestartpos = 0;
200 cd->linenumbertab = 0;
204 cd->maxstack = m->maxstack;
206 #if defined(ENABLE_THREADS)
207 cd->threadcritcurrent.next = NULL;
208 cd->threadcritcount = 0;
213 /* codegen_close ***************************************************************
217 *******************************************************************************/
219 void codegen_close(void)
221 /* TODO: release avl tree on i386 and x86_64 */
225 /* codegen_increase ************************************************************
229 *******************************************************************************/
231 void codegen_increase(codegendata *cd)
235 /* save old mcodebase pointer */
237 oldmcodebase = cd->mcodebase;
239 /* reallocate to new, doubled memory */
241 cd->mcodebase = DMREALLOC(cd->mcodebase,
246 cd->mcodeend = cd->mcodebase + cd->mcodesize;
248 /* set new mcodeptr */
250 cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
252 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
253 /* adjust the pointer to the last patcher position */
255 if (cd->lastmcodeptr != NULL)
256 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
261 /* codegen_ncode_increase ******************************************************
265 *******************************************************************************/
267 #if defined(ENABLE_INTRP)
268 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
272 /* save old ncodebase pointer */
274 oldncodebase = cd->ncodebase;
276 /* reallocate to new, doubled memory */
278 cd->ncodebase = DMREALLOC(cd->ncodebase,
284 /* return the new ncodeptr */
286 return (cd->ncodebase + (ncodeptr - oldncodebase));
291 /* codegen_add_branch_ref ******************************************************
293 Prepends an branch to the list.
295 *******************************************************************************/
297 void codegen_add_branch_ref(codegendata *cd, basicblock *target)
301 /* calculate the mpc of the branch instruction */
303 branchmpc = cd->mcodeptr - cd->mcodebase;
305 #if defined(ENABLE_JIT)
306 /* Check if the target basicblock has already a start pc, so the
307 jump is backward and we can resolve it immediately. */
309 if ((target->mpc >= 0)
310 # if defined(ENABLE_INTRP)
311 /* The interpreter uses absolute branches, so we do branch
312 resolving after the code and data segment move. */
318 md_codegen_patch_branch(cd, branchmpc, target->mpc);
323 branchref *br = DNEW(branchref);
325 br->branchpos = branchmpc;
326 br->next = target->branchrefs;
328 target->branchrefs = br;
333 /* codegen_resolve_branchrefs **************************************************
335 Resolves and patches the branch references of a given basic block.
337 *******************************************************************************/
339 void codegen_resolve_branchrefs(codegendata *cd, basicblock *bptr)
347 targetmpc = bptr->mpc;
349 for (br = bptr->branchrefs; br != NULL; br = br->next) {
350 branchmpc = br->branchpos;
352 md_codegen_patch_branch(cd, branchmpc, targetmpc);
357 /* codegen_add_exception_ref ***************************************************
359 Prepends an exception branch to the list.
361 *******************************************************************************/
363 static void codegen_add_exception_ref(codegendata *cd, s4 reg,
364 functionptr function)
369 branchmpc = cd->mcodeptr - cd->mcodebase;
371 er = DNEW(exceptionref);
373 er->branchpos = branchmpc;
375 er->function = function;
377 er->next = cd->exceptionrefs;
379 cd->exceptionrefs = er;
383 /* codegen_add_arithmeticexception_ref *****************************************
385 Adds an ArithmeticException branch to the list.
387 *******************************************************************************/
389 void codegen_add_arithmeticexception_ref(codegendata *cd)
391 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arithmeticexception);
395 /* codegen_add_arrayindexoutofboundsexception_ref ******************************
397 Adds an ArrayIndexOutOfBoundsException branch to the list.
399 *******************************************************************************/
401 void codegen_add_arrayindexoutofboundsexception_ref(codegendata *cd, s4 reg)
403 codegen_add_exception_ref(cd, reg,
404 STACKTRACE_inline_arrayindexoutofboundsexception);
408 /* codegen_add_arraystoreexception_ref *****************************************
410 Adds an ArrayStoreException branch to the list.
412 *******************************************************************************/
414 void codegen_add_arraystoreexception_ref(codegendata *cd)
416 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arraystoreexception);
420 /* codegen_add_classcastexception_ref ******************************************
422 Adds an ClassCastException branch to the list.
424 *******************************************************************************/
426 void codegen_add_classcastexception_ref(codegendata *cd, s4 reg)
428 codegen_add_exception_ref(cd, reg, STACKTRACE_inline_classcastexception);
432 /* codegen_add_nullpointerexception_ref ****************************************
434 Adds an NullPointerException branch to the list.
436 *******************************************************************************/
438 void codegen_add_nullpointerexception_ref(codegendata *cd)
440 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_nullpointerexception);
444 /* codegen_add_fillinstacktrace_ref ********************************************
446 Adds a fillInStackTrace branch to the list.
448 *******************************************************************************/
450 void codegen_add_fillinstacktrace_ref(codegendata *cd)
452 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_fillInStackTrace);
456 /* codegen_add_patch_ref *******************************************************
458 Appends a new patcher reference to the list of patching positions.
460 *******************************************************************************/
462 void codegen_add_patch_ref(codegendata *cd, functionptr patcher, voidptr ref,
468 branchmpc = cd->mcodeptr - cd->mcodebase;
472 pr->branchpos = branchmpc;
474 pr->patcher = patcher;
477 /* list_add_first(cd->patchrefs, pr); */
478 pr->next = cd->patchrefs;
481 #if defined(ENABLE_JIT) && (defined(__ALPHA__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__SPARC_64__) || defined(__X86_64__) || defined(__S390__))
482 /* Generate NOPs for opt_shownops. */
488 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
489 /* On some architectures the patcher stub call instruction might
490 be longer than the actual instruction generated. On this
491 architectures we store the last patcher call position and after
492 the basic block code generation is completed, we check the
493 range and maybe generate some nop's. */
495 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
500 /* methodtree_comparator *******************************************************
502 Comparator function used for the AVL tree of methods.
504 *******************************************************************************/
506 static s4 methodtree_comparator(const void *pc, const void *element)
508 methodtree_element *mte;
509 methodtree_element *mtepc;
511 mte = (methodtree_element *) element;
512 mtepc = (methodtree_element *) pc;
514 /* compare both startpc and endpc of pc, even if they have the same value,
515 otherwise the avl_probe sometimes thinks the element is already in the
519 /* On S390 addresses are 31 bit. Compare only 31 bits of value.
521 # define ADDR_MASK(a) ((a) & 0x7FFFFFFF)
523 # define ADDR_MASK(a) (a)
526 if (ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->startpc) &&
527 ADDR_MASK((long) mtepc->startpc) <= ADDR_MASK((long) mte->endpc) &&
528 ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->endpc) &&
529 ADDR_MASK((long) mtepc->endpc) <= ADDR_MASK((long) mte->endpc)) {
532 } else if (ADDR_MASK((long) mtepc->startpc) < ADDR_MASK((long) mte->startpc)) {
543 /* codegen_insertmethod ********************************************************
545 Insert the machine code range of a method into the AVL tree of methods.
547 *******************************************************************************/
549 void codegen_insertmethod(u1 *startpc, u1 *endpc)
551 methodtree_element *mte;
553 /* allocate new method entry */
555 mte = NEW(methodtree_element);
557 mte->startpc = startpc;
560 /* this function does not return an error, but asserts for
563 avl_insert(methodtree, mte);
567 /* codegen_get_pv_from_pc ******************************************************
569 Find the PV for the given PC by searching in the AVL tree of
572 *******************************************************************************/
574 u1 *codegen_get_pv_from_pc(u1 *pc)
576 methodtree_element mtepc;
577 methodtree_element *mte;
579 /* allocation of the search structure on the stack is much faster */
584 mte = avl_find(methodtree, &mtepc);
587 /* No method was found. Let's dump a stacktrace. */
589 log_println("We received a SIGSEGV and tried to handle it, but we were");
590 log_println("unable to find a Java method at:");
592 #if SIZEOF_VOID_P == 8
593 log_println("PC=0x%016lx", pc);
595 log_println("PC=0x%08x", pc);
598 log_println("Dumping the current stacktrace:");
600 stacktrace_dump_trace(THREADOBJECT);
602 vm_abort("Exiting...");
609 /* codegen_get_pv_from_pc_nocheck **********************************************
611 Find the PV for the given PC by searching in the AVL tree of
612 methods. This method does not check the return value and is used
615 *******************************************************************************/
617 u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
619 methodtree_element mtepc;
620 methodtree_element *mte;
622 /* allocation of the search structure on the stack is much faster */
627 mte = avl_find(methodtree, &mtepc);
636 /* codegen_set_replacement_point_notrap ****************************************
638 Record the position of a non-trappable replacement point.
640 *******************************************************************************/
642 #if defined(ENABLE_REPLACEMENT)
644 void codegen_set_replacement_point_notrap(codegendata *cd, s4 type)
646 void codegen_set_replacement_point_notrap(codegendata *cd)
649 assert(cd->replacementpoint);
650 assert(cd->replacementpoint->type == type);
651 assert(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP);
653 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
655 cd->replacementpoint++;
657 #endif /* defined(ENABLE_REPLACEMENT) */
660 /* codegen_set_replacement_point ***********************************************
662 Record the position of a trappable replacement point.
664 *******************************************************************************/
666 #if defined(ENABLE_REPLACEMENT)
668 void codegen_set_replacement_point(codegendata *cd, s4 type)
670 void codegen_set_replacement_point(codegendata *cd)
673 assert(cd->replacementpoint);
674 assert(cd->replacementpoint->type == type);
675 assert(!(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP));
677 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
679 cd->replacementpoint++;
681 /* XXX assert(cd->lastmcodeptr <= cd->mcodeptr); */
683 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
685 #endif /* defined(ENABLE_REPLACEMENT) */
688 /* codegen_finish **************************************************************
690 Finishes the code generation. A new memory, large enough for both
691 data and code, is allocated and data and code are copied together
692 to their final layout, unresolved jumps are resolved, ...
694 *******************************************************************************/
696 void codegen_finish(jitdata *jd)
701 #if defined(ENABLE_INTRP)
710 /* get required compiler data */
715 /* prevent compiler warning */
717 #if defined(ENABLE_INTRP)
721 /* calculate the code length */
723 mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
725 #if defined(ENABLE_THREADS)
726 extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
731 #if defined(ENABLE_STATISTICS)
733 count_code_len += mcodelen;
734 count_data_len += cd->dseglen;
738 alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
740 #if defined(ENABLE_INTRP)
742 ncodelen = cd->ncodeptr - cd->ncodebase;
744 ncodelen = 0; /* avoid compiler warning */
748 cd->dseglen = MEMORY_ALIGN(cd->dseglen, MAX_ALIGN);
749 alignedlen = alignedmcodelen + cd->dseglen;
751 #if defined(ENABLE_INTRP)
753 alignedlen += ncodelen;
757 /* allocate new memory */
759 code->mcodelength = mcodelen + cd->dseglen;
760 code->mcode = CNEW(u1, alignedlen + extralen);
762 /* set the entrypoint of the method */
764 assert(code->entrypoint == NULL);
765 code->entrypoint = epoint = (code->mcode + cd->dseglen);
767 /* fill the data segment (code->entrypoint must already be set!) */
771 /* copy code to the new location */
773 MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
775 #if defined(ENABLE_INTRP)
776 /* relocate native dynamic superinstruction code (if any) */
779 cd->mcodebase = code->entrypoint;
782 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
784 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
786 /* flush the instruction and data caches */
788 md_cacheflush(ncodebase, ncodelen);
790 /* set some cd variables for dynamic_super_rerwite */
792 cd->ncodebase = ncodebase;
795 cd->ncodebase = NULL;
798 dynamic_super_rewrite(cd);
802 /* jump table resolving */
804 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
805 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
806 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
808 /* line number table resolving */
814 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
816 target = lr->targetmpc;
817 /* if the entry contains an mcode pointer (normal case), resolve it */
818 /* (see doc/inlining_stacktrace.txt for details) */
819 if (lr->linenumber >= -2) {
820 target += (ptrint) epoint;
822 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
823 (functionptr) target;
826 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
827 (functionptr) ((ptrint) epoint + cd->linenumbertab);
829 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
832 #if defined(ENABLE_REPLACEMENT)
833 /* replacement point resolving */
838 code->replacementstubs += (ptrint) epoint;
840 rp = code->rplpoints;
841 for (i=0; i<code->rplpointcount; ++i, ++rp) {
842 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
845 #endif /* defined(ENABLE_REPLACEMENT) */
847 /* add method into methodtree to find the entrypoint */
849 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
851 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
852 /* resolve data segment references */
854 dseg_resolve_datareferences(jd);
857 #if defined(ENABLE_THREADS)
859 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
861 codegen_critical_section_t *nt = cd->threadcrit;
863 for (i = 0; i < cd->threadcritcount; i++) {
864 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
865 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
866 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
867 critical_register_critical_section(n);
874 /* flush the instruction and data caches */
876 md_cacheflush(code->mcode, code->mcodelength);
880 /* codegen_createnativestub ****************************************************
882 Wrapper for createnativestub.
885 the codeinfo representing the stub code.
887 *******************************************************************************/
889 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
898 /* mark dump memory */
900 dumpsize = dump_size();
905 jd->cd = DNEW(codegendata);
906 jd->rd = DNEW(registerdata);
909 /* Allocate codeinfo memory from the heap as we need to keep them. */
911 jd->code = code_codeinfo_new(m); /* XXX check allocation */
913 /* get required compiler data */
917 /* set the flags for the current JIT run */
919 #if defined(ENABLE_PROFILING)
921 jd->flags |= JITDATA_FLAG_INSTRUMENT;
925 jd->flags |= JITDATA_FLAG_VERBOSECALL;
927 /* setup code generation stuff */
929 #if defined(ENABLE_JIT)
930 # if defined(ENABLE_INTRP)
938 /* create new method descriptor with additional native parameters */
941 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
943 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
944 md->paramcount * sizeof(typedesc) +
945 nativeparams * sizeof(typedesc));
947 nmd->paramcount = md->paramcount + nativeparams;
949 nmd->params = DMNEW(paramdesc, nmd->paramcount);
951 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
953 if (m->flags & ACC_STATIC)
954 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
956 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
959 #if defined(ENABLE_JIT)
960 # if defined(ENABLE_INTRP)
963 /* pre-allocate the arguments for the native ABI */
965 md_param_alloc_native(nmd);
968 /* generate the code */
970 #if defined(ENABLE_JIT)
971 # if defined(ENABLE_INTRP)
973 code->entrypoint = intrp_createnativestub(f, jd, nmd);
976 code->entrypoint = createnativestub(f, jd, nmd);
978 code->entrypoint = intrp_createnativestub(f, jd, nmd);
981 #if defined(ENABLE_STATISTICS)
983 count_nstub_len += code->mcodelength;
987 /* disassemble native stub */
989 if (opt_shownativestub) {
990 #if defined(ENABLE_DISASSEMBLER)
991 codegen_disassemble_nativestub(m,
992 (u1 *) (ptrint) code->entrypoint,
993 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
996 /* show data segment */
998 if (opt_showddatasegment)
1001 #endif /* !defined(NDEBUG) */
1003 /* release memory */
1005 dump_release(dumpsize);
1007 /* return native stub code */
1013 /* codegen_disassemble_nativestub **********************************************
1015 Disassembles the generated native stub.
1017 *******************************************************************************/
1019 #if defined(ENABLE_DISASSEMBLER)
1020 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
1022 printf("Native stub: ");
1023 utf_fprint_printable_ascii_classname(stdout, m->class->name);
1025 utf_fprint_printable_ascii(stdout, m->name);
1026 utf_fprint_printable_ascii(stdout, m->descriptor);
1027 printf("\n\nLength: %d\n\n", (s4) (end - start));
1029 DISASSEMBLE(start, end);
1034 /* codegen_start_native_call ***************************************************
1036 Prepares the stuff required for a native (JNI) function call:
1038 - adds a stackframe info structure to the chain, for stacktraces
1039 - prepares the local references table on the stack
1041 The layout of the native stub stackframe should look like this:
1043 +---------------------------+ <- SP (of parent Java function)
1045 +---------------------------+
1047 | stackframe info structure |
1049 +---------------------------+
1051 | local references table |
1053 +---------------------------+
1055 | arguments (if any) |
1057 +---------------------------+ <- SP (native stub)
1059 *******************************************************************************/
1061 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
1063 stackframeinfo *sfi;
1064 localref_table *lrt;
1066 /* get data structures from stack */
1068 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1069 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1070 sizeof(localref_table));
1072 /* add a stackframeinfo to the chain */
1074 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1076 #if defined(ENABLE_JAVASE)
1077 /* add current JNI local references table to this thread */
1079 lrt->capacity = LOCALREFTABLE_CAPACITY;
1081 lrt->localframes = 1;
1082 lrt->prev = LOCALREFTABLE;
1084 /* clear the references array (memset is faster the a for-loop) */
1086 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1088 LOCALREFTABLE = lrt;
1091 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1092 /* set the native world flag */
1094 THREADOBJECT->flags |= THREAD_FLAG_IN_NATIVE;
1099 /* codegen_finish_native_call **************************************************
1101 Removes the stuff required for a native (JNI) function call.
1102 Additionally it checks for an exceptions and in case, get the
1103 exception object and clear the pointer.
1105 *******************************************************************************/
1107 java_objectheader *codegen_finish_native_call(u1 *datasp)
1109 stackframeinfo *sfi;
1110 stackframeinfo **psfi;
1111 localref_table *lrt;
1112 localref_table *plrt;
1114 java_objectheader *e;
1116 /* get data structures from stack */
1118 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1119 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1120 sizeof(localref_table));
1122 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1123 /* clear the native world flag */
1125 THREADOBJECT->flags &= ~THREAD_FLAG_IN_NATIVE;
1128 /* remove current stackframeinfo from chain */
1130 psfi = STACKFRAMEINFO;
1134 #if defined(ENABLE_JAVASE)
1135 /* release JNI local references tables for this thread */
1137 lrt = LOCALREFTABLE;
1139 /* release all current local frames */
1141 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1142 /* get previous frame */
1146 /* Clear all reference entries (only for tables allocated on
1149 if (localframes > 1)
1150 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1154 /* set new local references table */
1159 /* now store the previous local frames in the thread structure */
1161 LOCALREFTABLE = lrt;
1164 /* get the exception and return it */
1166 e = exceptions_get_and_clear_exception();
1172 /* removecompilerstub **********************************************************
1174 Deletes a compilerstub from memory (simply by freeing it).
1176 *******************************************************************************/
1178 void removecompilerstub(u1 *stub)
1180 /* pass size 1 to keep the intern function happy */
1182 CFREE((void *) stub, 1);
1186 /* removenativestub ************************************************************
1188 Removes a previously created native-stub from memory.
1190 *******************************************************************************/
1192 void removenativestub(u1 *stub)
1194 /* pass size 1 to keep the intern function happy */
1196 CFREE((void *) stub, 1);
1200 /* codegen_reg_of_var **********************************************************
1202 This function determines a register, to which the result of an
1203 operation should go, when it is ultimatively intended to store the
1204 result in pseudoregister v. If v is assigned to an actual
1205 register, this register will be returned. Otherwise (when v is
1206 spilled) this function returns tempregnum. If not already done,
1207 regoff and flags are set in the stack location.
1209 On ARM we have to check if a long/double variable is splitted
1210 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1211 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1212 cases. (michi 2005/07/24)
1214 *******************************************************************************/
1216 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
1220 /* Do we have to generate a conditional move? Yes, then always
1221 return the temporary register. The real register is identified
1222 during the store. */
1224 if (opcode & ICMD_CONDITION_MASK)
1228 if (!(v->flags & INMEMORY)) {
1229 #if defined(__ARM__) && defined(__ARMEL__)
1230 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
1231 return PACK_REGS(GET_LOW_REG(v->vv.regoff),
1232 GET_HIGH_REG(tempregnum));
1234 #if defined(__ARM__) && defined(__ARMEB__)
1235 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
1236 return PACK_REGS(GET_LOW_REG(tempregnum),
1237 GET_HIGH_REG(v->vv.regoff));
1239 return v->vv.regoff;
1242 #if defined(ENABLE_STATISTICS)
1244 count_spills_read++;
1250 /* codegen_reg_of_dst **********************************************************
1252 This function determines a register, to which the result of an
1253 operation should go, when it is ultimatively intended to store the
1254 result in iptr->dst.var. If dst.var is assigned to an actual
1255 register, this register will be returned. Otherwise (when it is
1256 spilled) this function returns tempregnum. If not already done,
1257 regoff and flags are set in the stack location.
1259 On ARM we have to check if a long/double variable is splitted
1260 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1261 register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
1262 cases. (michi 2005/07/24)
1264 *******************************************************************************/
1266 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1268 return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
1272 #if defined(ENABLE_THREADS)
1273 void codegen_threadcritrestart(codegendata *cd, int offset)
1275 cd->threadcritcurrent.mcoderestart = offset;
1279 void codegen_threadcritstart(codegendata *cd, int offset)
1281 cd->threadcritcurrent.mcodebegin = offset;
1285 void codegen_threadcritstop(codegendata *cd, int offset)
1287 cd->threadcritcurrent.next = cd->threadcrit;
1288 cd->threadcritcurrent.mcodeend = offset;
1289 cd->threadcrit = DNEW(codegen_critical_section_t);
1290 *(cd->threadcrit) = cd->threadcritcurrent;
1291 cd->threadcritcount++;
1297 * These are local overrides for various environment variables in Emacs.
1298 * Please do not remove this and leave it at the end of the file, where
1299 * Emacs will automagically detect them.
1300 * ---------------------------------------------------------------------
1303 * indent-tabs-mode: t
1307 * vim:noexpandtab:sw=4:ts=4: