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 7330 2007-02-11 21:39:54Z twisti $
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/asmpart.h"
81 #include "vm/jit/codegen-common.h"
83 #if defined(ENABLE_DISASSEMBLER)
84 # include "vm/jit/disass.h"
87 #include "vm/jit/dseg.h"
88 #include "vm/jit/jit.h"
89 #include "vm/jit/md.h"
90 #include "vm/jit/replace.h"
91 #include "vm/jit/stacktrace.h"
93 #if defined(ENABLE_INTRP)
94 #include "vm/jit/intrp/intrp.h"
97 #include "vmcore/method.h"
98 #include "vmcore/options.h"
100 #if defined(ENABLE_STATISTICS)
101 # include "vmcore/statistics.h"
105 /* in this tree we store all method addresses *********************************/
107 static avl_tree *methodtree = NULL;
108 static s4 methodtree_comparator(const void *pc, const void *element);
111 /* codegen_init ****************************************************************
115 *******************************************************************************/
117 void codegen_init(void)
119 /* this tree is global, not method specific */
122 #if defined(ENABLE_JIT)
123 methodtree_element *mte;
126 methodtree = avl_create(&methodtree_comparator);
128 #if defined(ENABLE_JIT)
129 /* insert asm_vm_call_method */
131 mte = NEW(methodtree_element);
133 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
134 mte->endpc = (u1 *) ((ptrint) asm_call_jit_compiler - 1);
136 avl_insert(methodtree, mte);
137 #endif /* defined(ENABLE_JIT) */
142 /* codegen_setup ***************************************************************
144 Allocates and initialises code area, data area and references.
146 *******************************************************************************/
148 void codegen_setup(jitdata *jd)
153 /* get required compiler data */
158 cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
159 cd->mcodeend = cd->mcodebase + MCODEINITSIZE;
160 cd->mcodesize = MCODEINITSIZE;
162 /* initialize mcode variables */
164 cd->mcodeptr = cd->mcodebase;
165 cd->lastmcodeptr = cd->mcodebase;
167 #if defined(ENABLE_INTRP)
168 /* native dynamic superinstructions variables */
171 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
172 cd->ncodesize = NCODEINITSIZE;
174 /* initialize ncode variables */
176 cd->ncodeptr = cd->ncodebase;
178 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
179 cd->superstarts = NULL;
186 cd->jumpreferences = NULL;
188 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
189 cd->datareferences = NULL;
192 cd->exceptionrefs = NULL;
193 /* cd->patchrefs = list_create_dump(OFFSET(patchref, linkage)); */
194 cd->patchrefs = NULL;
196 cd->linenumberreferences = NULL;
197 cd->linenumbertablesizepos = 0;
198 cd->linenumbertablestartpos = 0;
199 cd->linenumbertab = 0;
203 cd->maxstack = m->maxstack;
205 #if defined(ENABLE_THREADS)
206 cd->threadcritcurrent.next = NULL;
207 cd->threadcritcount = 0;
212 /* codegen_close ***************************************************************
216 *******************************************************************************/
218 void codegen_close(void)
220 /* TODO: release avl tree on i386 and x86_64 */
224 /* codegen_increase ************************************************************
228 *******************************************************************************/
230 void codegen_increase(codegendata *cd)
234 /* save old mcodebase pointer */
236 oldmcodebase = cd->mcodebase;
238 /* reallocate to new, doubled memory */
240 cd->mcodebase = DMREALLOC(cd->mcodebase,
245 cd->mcodeend = cd->mcodebase + cd->mcodesize;
247 /* set new mcodeptr */
249 cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
251 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
252 /* adjust the pointer to the last patcher position */
254 if (cd->lastmcodeptr != NULL)
255 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
260 /* codegen_ncode_increase ******************************************************
264 *******************************************************************************/
266 #if defined(ENABLE_INTRP)
267 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
271 /* save old ncodebase pointer */
273 oldncodebase = cd->ncodebase;
275 /* reallocate to new, doubled memory */
277 cd->ncodebase = DMREALLOC(cd->ncodebase,
283 /* return the new ncodeptr */
285 return (cd->ncodebase + (ncodeptr - oldncodebase));
290 /* codegen_add_branch_ref ******************************************************
292 Prepends an branch to the list.
294 *******************************************************************************/
296 void codegen_add_branch_ref(codegendata *cd, basicblock *target)
300 /* calculate the mpc of the branch instruction */
302 branchmpc = cd->mcodeptr - cd->mcodebase;
304 #if defined(ENABLE_JIT)
305 /* Check if the target basicblock has already a start pc, so the
306 jump is backward and we can resolve it immediately. */
308 if ((target->mpc >= 0)
309 # if defined(ENABLE_INTRP)
310 /* The interpreter uses absolute branches, so we do branch
311 resolving after the code and data segment move. */
317 md_codegen_patch_branch(cd, branchmpc, target->mpc);
322 branchref *br = DNEW(branchref);
324 br->branchpos = branchmpc;
325 br->next = target->branchrefs;
327 target->branchrefs = br;
332 /* codegen_resolve_branchrefs **************************************************
334 Resolves and patches the branch references of a given basic block.
336 *******************************************************************************/
338 void codegen_resolve_branchrefs(codegendata *cd, basicblock *bptr)
346 targetmpc = bptr->mpc;
348 for (br = bptr->branchrefs; br != NULL; br = br->next) {
349 branchmpc = br->branchpos;
351 md_codegen_patch_branch(cd, branchmpc, targetmpc);
356 /* codegen_add_exception_ref ***************************************************
358 Prepends an exception branch to the list.
360 *******************************************************************************/
362 static void codegen_add_exception_ref(codegendata *cd, s4 reg,
363 functionptr function)
368 branchmpc = cd->mcodeptr - cd->mcodebase;
370 er = DNEW(exceptionref);
372 er->branchpos = branchmpc;
374 er->function = function;
376 er->next = cd->exceptionrefs;
378 cd->exceptionrefs = er;
382 /* codegen_add_arithmeticexception_ref *****************************************
384 Adds an ArithmeticException branch to the list.
386 *******************************************************************************/
388 void codegen_add_arithmeticexception_ref(codegendata *cd)
390 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arithmeticexception);
394 /* codegen_add_arrayindexoutofboundsexception_ref ******************************
396 Adds an ArrayIndexOutOfBoundsException branch to the list.
398 *******************************************************************************/
400 void codegen_add_arrayindexoutofboundsexception_ref(codegendata *cd, s4 reg)
402 codegen_add_exception_ref(cd, reg,
403 STACKTRACE_inline_arrayindexoutofboundsexception);
407 /* codegen_add_arraystoreexception_ref *****************************************
409 Adds an ArrayStoreException branch to the list.
411 *******************************************************************************/
413 void codegen_add_arraystoreexception_ref(codegendata *cd)
415 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arraystoreexception);
419 /* codegen_add_classcastexception_ref ******************************************
421 Adds an ClassCastException branch to the list.
423 *******************************************************************************/
425 void codegen_add_classcastexception_ref(codegendata *cd, s4 reg)
427 codegen_add_exception_ref(cd, reg, STACKTRACE_inline_classcastexception);
431 /* codegen_add_nullpointerexception_ref ****************************************
433 Adds an NullPointerException branch to the list.
435 *******************************************************************************/
437 void codegen_add_nullpointerexception_ref(codegendata *cd)
439 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_nullpointerexception);
443 /* codegen_add_fillinstacktrace_ref ********************************************
445 Adds a fillInStackTrace branch to the list.
447 *******************************************************************************/
449 void codegen_add_fillinstacktrace_ref(codegendata *cd)
451 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_fillInStackTrace);
455 /* codegen_add_patch_ref *******************************************************
457 Appends a new patcher reference to the list of patching positions.
459 *******************************************************************************/
461 void codegen_add_patch_ref(codegendata *cd, functionptr patcher, voidptr ref,
467 branchmpc = cd->mcodeptr - cd->mcodebase;
471 pr->branchpos = branchmpc;
473 pr->patcher = patcher;
476 /* list_add_first(cd->patchrefs, pr); */
477 pr->next = cd->patchrefs;
480 #if defined(ENABLE_JIT) && (defined(__ALPHA__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__X86_64__) || defined(__S390__))
481 /* Generate NOPs for opt_shownops. */
487 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
488 /* On some architectures the patcher stub call instruction might
489 be longer than the actual instruction generated. On this
490 architectures we store the last patcher call position and after
491 the basic block code generation is completed, we check the
492 range and maybe generate some nop's. */
494 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
499 /* methodtree_comparator *******************************************************
501 Comparator function used for the AVL tree of methods.
503 *******************************************************************************/
505 static s4 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 sometimes thinks the element is already in the
518 /* On S390 addresses are 31 bit, and therefore are ambigue. */
519 # define ADDR_MASK(a) ((a) & 0x7FFFFFFF)
521 # define ADDR_MASK(a) (a)
524 if (ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->startpc) &&
525 ADDR_MASK((long) mtepc->startpc) <= ADDR_MASK((long) mte->endpc) &&
526 ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->endpc) &&
527 ADDR_MASK((long) mtepc->endpc) <= ADDR_MASK((long) mte->endpc)) {
530 } else if (ADDR_MASK((long) mtepc->startpc) < ADDR_MASK((long) mte->startpc)) {
541 /* codegen_insertmethod ********************************************************
543 Insert the machine code range of a method into the AVL tree of methods.
545 *******************************************************************************/
547 void codegen_insertmethod(u1 *startpc, u1 *endpc)
549 methodtree_element *mte;
551 /* allocate new method entry */
553 mte = NEW(methodtree_element);
555 mte->startpc = startpc;
558 /* this function does not return an error, but asserts for
561 avl_insert(methodtree, mte);
565 /* codegen_get_pv_from_pc ******************************************************
567 Find the PV for the given PC by searching in the AVL tree of
570 *******************************************************************************/
572 u1 *codegen_get_pv_from_pc(u1 *pc)
574 methodtree_element mtepc;
575 methodtree_element *mte;
577 /* allocation of the search structure on the stack is much faster */
582 mte = avl_find(methodtree, &mtepc);
585 /* No method was found. Let's dump a stacktrace. */
587 log_println("We received a SIGSEGV and tried to handle it, but we were");
588 log_println("unable to find a Java method at:");
590 #if SIZEOF_VOID_P == 8
591 log_println("PC=0x%016lx", pc);
593 log_println("PC=0x%08x", pc);
596 log_println("Dumping the current stacktrace:");
598 stacktrace_dump_trace(THREADOBJECT);
600 vm_abort("Exiting...");
607 /* codegen_get_pv_from_pc_nocheck **********************************************
609 Find the PV for the given PC by searching in the AVL tree of
610 methods. This method does not check the return value and is used
613 *******************************************************************************/
615 u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
617 methodtree_element mtepc;
618 methodtree_element *mte;
620 /* allocation of the search structure on the stack is much faster */
625 mte = avl_find(methodtree, &mtepc);
634 /* codegen_set_replacement_point_notrap ****************************************
636 Record the position of a non-trappable replacement point.
638 *******************************************************************************/
640 #if defined(ENABLE_REPLACEMENT)
642 void codegen_set_replacement_point_notrap(codegendata *cd, s4 type)
644 void codegen_set_replacement_point_notrap(codegendata *cd)
647 assert(cd->replacementpoint);
648 assert(cd->replacementpoint->type == type);
649 assert(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP);
651 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
653 cd->replacementpoint++;
655 #endif /* defined(ENABLE_REPLACEMENT) */
658 /* codegen_set_replacement_point ***********************************************
660 Record the position of a trappable replacement point.
662 *******************************************************************************/
664 #if defined(ENABLE_REPLACEMENT)
666 void codegen_set_replacement_point(codegendata *cd, s4 type)
668 void codegen_set_replacement_point(codegendata *cd)
671 assert(cd->replacementpoint);
672 assert(cd->replacementpoint->type == type);
673 assert(!(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP));
675 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
677 cd->replacementpoint++;
679 /* XXX assert(cd->lastmcodeptr <= cd->mcodeptr); */
681 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
683 #endif /* defined(ENABLE_REPLACEMENT) */
686 /* codegen_finish **************************************************************
688 Finishes the code generation. A new memory, large enough for both
689 data and code, is allocated and data and code are copied together
690 to their final layout, unresolved jumps are resolved, ...
692 *******************************************************************************/
694 void codegen_finish(jitdata *jd)
699 #if defined(ENABLE_INTRP)
708 /* get required compiler data */
713 /* prevent compiler warning */
715 #if defined(ENABLE_INTRP)
719 /* calculate the code length */
721 mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
723 #if defined(ENABLE_THREADS)
724 extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
729 #if defined(ENABLE_STATISTICS)
731 count_code_len += mcodelen;
732 count_data_len += cd->dseglen;
736 alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
738 #if defined(ENABLE_INTRP)
740 ncodelen = cd->ncodeptr - cd->ncodebase;
742 ncodelen = 0; /* avoid compiler warning */
746 cd->dseglen = MEMORY_ALIGN(cd->dseglen, MAX_ALIGN);
747 alignedlen = alignedmcodelen + cd->dseglen;
749 #if defined(ENABLE_INTRP)
751 alignedlen += ncodelen;
755 /* allocate new memory */
757 code->mcodelength = mcodelen + cd->dseglen;
758 code->mcode = CNEW(u1, alignedlen + extralen);
760 /* set the entrypoint of the method */
762 assert(code->entrypoint == NULL);
763 code->entrypoint = epoint = (code->mcode + cd->dseglen);
765 /* fill the data segment (code->entrypoint must already be set!) */
769 /* copy code to the new location */
771 MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
773 #if defined(ENABLE_INTRP)
774 /* relocate native dynamic superinstruction code (if any) */
777 cd->mcodebase = code->entrypoint;
780 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
782 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
784 /* flush the instruction and data caches */
786 md_cacheflush(ncodebase, ncodelen);
788 /* set some cd variables for dynamic_super_rerwite */
790 cd->ncodebase = ncodebase;
793 cd->ncodebase = NULL;
796 dynamic_super_rewrite(cd);
800 /* jump table resolving */
802 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
803 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
804 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
806 /* line number table resolving */
812 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
814 target = lr->targetmpc;
815 /* if the entry contains an mcode pointer (normal case), resolve it */
816 /* (see doc/inlining_stacktrace.txt for details) */
817 if (lr->linenumber >= -2) {
818 target += (ptrint) epoint;
820 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
821 (functionptr) target;
824 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
825 (functionptr) ((ptrint) epoint + cd->linenumbertab);
827 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
830 #if defined(ENABLE_REPLACEMENT)
831 /* replacement point resolving */
836 code->replacementstubs += (ptrint) epoint;
838 rp = code->rplpoints;
839 for (i=0; i<code->rplpointcount; ++i, ++rp) {
840 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
843 #endif /* defined(ENABLE_REPLACEMENT) */
845 /* add method into methodtree to find the entrypoint */
847 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
849 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
850 /* resolve data segment references */
852 dseg_resolve_datareferences(jd);
855 #if defined(ENABLE_THREADS)
857 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
859 codegen_critical_section_t *nt = cd->threadcrit;
861 for (i = 0; i < cd->threadcritcount; i++) {
862 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
863 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
864 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
865 critical_register_critical_section(n);
872 /* flush the instruction and data caches */
874 md_cacheflush(code->mcode, code->mcodelength);
878 /* codegen_createnativestub ****************************************************
880 Wrapper for createnativestub.
883 the codeinfo representing the stub code.
885 *******************************************************************************/
887 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
896 /* mark dump memory */
898 dumpsize = dump_size();
903 jd->cd = DNEW(codegendata);
904 jd->rd = DNEW(registerdata);
907 /* Allocate codeinfo memory from the heap as we need to keep them. */
909 jd->code = code_codeinfo_new(m); /* XXX check allocation */
911 /* get required compiler data */
915 /* set the flags for the current JIT run */
917 #if defined(ENABLE_PROFILING)
919 jd->flags |= JITDATA_FLAG_INSTRUMENT;
923 jd->flags |= JITDATA_FLAG_VERBOSECALL;
925 /* setup code generation stuff */
927 #if defined(ENABLE_JIT)
928 # if defined(ENABLE_INTRP)
936 /* create new method descriptor with additional native parameters */
939 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
941 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
942 md->paramcount * sizeof(typedesc) +
943 nativeparams * sizeof(typedesc));
945 nmd->paramcount = md->paramcount + nativeparams;
947 nmd->params = DMNEW(paramdesc, nmd->paramcount);
949 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
951 if (m->flags & ACC_STATIC)
952 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
954 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
957 #if defined(ENABLE_JIT)
958 # if defined(ENABLE_INTRP)
961 /* pre-allocate the arguments for the native ABI */
963 md_param_alloc_native(nmd);
966 /* generate the code */
968 #if defined(ENABLE_JIT)
969 # if defined(ENABLE_INTRP)
971 code->entrypoint = intrp_createnativestub(f, jd, nmd);
974 code->entrypoint = createnativestub(f, jd, nmd);
976 code->entrypoint = intrp_createnativestub(f, jd, nmd);
979 #if defined(ENABLE_STATISTICS)
981 count_nstub_len += code->mcodelength;
985 /* disassemble native stub */
987 if (opt_shownativestub) {
988 #if defined(ENABLE_DISASSEMBLER)
989 codegen_disassemble_nativestub(m,
990 (u1 *) (ptrint) code->entrypoint,
991 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
994 /* show data segment */
996 if (opt_showddatasegment)
999 #endif /* !defined(NDEBUG) */
1001 /* release memory */
1003 dump_release(dumpsize);
1005 /* return native stub code */
1011 /* codegen_disassemble_nativestub **********************************************
1013 Disassembles the generated native stub.
1015 *******************************************************************************/
1017 #if defined(ENABLE_DISASSEMBLER)
1018 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
1020 printf("Native stub: ");
1021 utf_fprint_printable_ascii_classname(stdout, m->class->name);
1023 utf_fprint_printable_ascii(stdout, m->name);
1024 utf_fprint_printable_ascii(stdout, m->descriptor);
1025 printf("\n\nLength: %d\n\n", (s4) (end - start));
1027 DISASSEMBLE(start, end);
1032 /* codegen_start_native_call ***************************************************
1034 Prepares the stuff required for a native (JNI) function call:
1036 - adds a stackframe info structure to the chain, for stacktraces
1037 - prepares the local references table on the stack
1039 The layout of the native stub stackframe should look like this:
1041 +---------------------------+ <- SP (of parent Java function)
1043 +---------------------------+
1045 | stackframe info structure |
1047 +---------------------------+
1049 | local references table |
1051 +---------------------------+
1053 | arguments (if any) |
1055 +---------------------------+ <- SP (native stub)
1057 *******************************************************************************/
1059 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
1061 stackframeinfo *sfi;
1062 localref_table *lrt;
1064 /* get data structures from stack */
1066 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1067 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1068 sizeof(localref_table));
1070 /* add a stackframeinfo to the chain */
1072 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1074 #if defined(ENABLE_JAVASE)
1075 /* add current JNI local references table to this thread */
1077 lrt->capacity = LOCALREFTABLE_CAPACITY;
1079 lrt->localframes = 1;
1080 lrt->prev = LOCALREFTABLE;
1082 /* clear the references array (memset is faster the a for-loop) */
1084 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1086 LOCALREFTABLE = lrt;
1091 /* codegen_finish_native_call **************************************************
1093 Removes the stuff required for a native (JNI) function call.
1094 Additionally it checks for an exceptions and in case, get the
1095 exception object and clear the pointer.
1097 *******************************************************************************/
1099 java_objectheader *codegen_finish_native_call(u1 *datasp)
1101 stackframeinfo *sfi;
1102 stackframeinfo **psfi;
1103 localref_table *lrt;
1104 localref_table *plrt;
1106 java_objectheader *e;
1108 /* get data structures from stack */
1110 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1111 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1112 sizeof(localref_table));
1114 /* remove current stackframeinfo from chain */
1116 psfi = STACKFRAMEINFO;
1120 #if defined(ENABLE_JAVASE)
1121 /* release JNI local references tables for this thread */
1123 lrt = LOCALREFTABLE;
1125 /* release all current local frames */
1127 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1128 /* get previous frame */
1132 /* Clear all reference entries (only for tables allocated on
1135 if (localframes > 1)
1136 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1140 /* set new local references table */
1145 /* now store the previous local frames in the thread structure */
1147 LOCALREFTABLE = lrt;
1150 /* get the exception and return it */
1152 e = exceptions_get_and_clear_exception();
1158 /* removecompilerstub **********************************************************
1160 Deletes a compilerstub from memory (simply by freeing it).
1162 *******************************************************************************/
1164 void removecompilerstub(u1 *stub)
1166 /* pass size 1 to keep the intern function happy */
1168 CFREE((void *) stub, 1);
1172 /* removenativestub ************************************************************
1174 Removes a previously created native-stub from memory.
1176 *******************************************************************************/
1178 void removenativestub(u1 *stub)
1180 /* pass size 1 to keep the intern function happy */
1182 CFREE((void *) stub, 1);
1186 /* codegen_reg_of_var **********************************************************
1188 This function determines a register, to which the result of an
1189 operation should go, when it is ultimatively intended to store the
1190 result in pseudoregister v. If v is assigned to an actual
1191 register, this register will be returned. Otherwise (when v is
1192 spilled) this function returns tempregnum. If not already done,
1193 regoff and flags are set in the stack location.
1195 On ARM we have to check if a long/double variable is splitted
1196 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1197 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1198 cases. (michi 2005/07/24)
1200 *******************************************************************************/
1202 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
1206 /* Do we have to generate a conditional move? Yes, then always
1207 return the temporary register. The real register is identified
1208 during the store. */
1210 if (opcode & ICMD_CONDITION_MASK)
1214 if (!(v->flags & INMEMORY)) {
1215 #if defined(__ARM__) && defined(__ARMEL__)
1216 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
1217 return PACK_REGS(GET_LOW_REG(v->vv.regoff),
1218 GET_HIGH_REG(tempregnum));
1220 #if defined(__ARM__) && defined(__ARMEB__)
1221 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
1222 return PACK_REGS(GET_LOW_REG(tempregnum),
1223 GET_HIGH_REG(v->vv.regoff));
1225 return v->vv.regoff;
1228 #if defined(ENABLE_STATISTICS)
1230 count_spills_read++;
1236 /* codegen_reg_of_dst **********************************************************
1238 This function determines a register, to which the result of an
1239 operation should go, when it is ultimatively intended to store the
1240 result in iptr->dst.var. If dst.var is assigned to an actual
1241 register, this register will be returned. Otherwise (when it is
1242 spilled) this function returns tempregnum. If not already done,
1243 regoff and flags are set in the stack location.
1245 On ARM we have to check if a long/double variable is splitted
1246 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1247 register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
1248 cases. (michi 2005/07/24)
1250 *******************************************************************************/
1252 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1254 return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
1258 #if defined(ENABLE_THREADS)
1259 void codegen_threadcritrestart(codegendata *cd, int offset)
1261 cd->threadcritcurrent.mcoderestart = offset;
1265 void codegen_threadcritstart(codegendata *cd, int offset)
1267 cd->threadcritcurrent.mcodebegin = offset;
1271 void codegen_threadcritstop(codegendata *cd, int offset)
1273 cd->threadcritcurrent.next = cd->threadcrit;
1274 cd->threadcritcurrent.mcodeend = offset;
1275 cd->threadcrit = DNEW(codegen_critical_section_t);
1276 *(cd->threadcrit) = cd->threadcritcurrent;
1277 cd->threadcritcount++;
1283 * These are local overrides for various environment variables in Emacs.
1284 * Please do not remove this and leave it at the end of the file, where
1285 * Emacs will automagically detect them.
1286 * ---------------------------------------------------------------------
1289 * indent-tabs-mode: t
1293 * vim:noexpandtab:sw=4:ts=4: