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 7323 2007-02-11 17:52:12Z pm $
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/stacktrace.h"
90 #include "vm/jit/replace.h"
92 #if defined(ENABLE_INTRP)
93 #include "vm/jit/intrp/intrp.h"
96 #include "vmcore/method.h"
97 #include "vmcore/options.h"
99 #if defined(ENABLE_STATISTICS)
100 # include "vmcore/statistics.h"
104 /* in this tree we store all method addresses *********************************/
106 static avl_tree *methodtree = NULL;
107 static s4 methodtree_comparator(const void *pc, const void *element);
110 /* codegen_init ****************************************************************
114 *******************************************************************************/
116 void codegen_init(void)
118 /* this tree is global, not method specific */
121 #if defined(ENABLE_JIT)
122 methodtree_element *mte;
125 methodtree = avl_create(&methodtree_comparator);
127 #if defined(ENABLE_JIT)
128 /* insert asm_vm_call_method */
130 mte = NEW(methodtree_element);
132 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
133 mte->endpc = (u1 *) ((ptrint) asm_call_jit_compiler - 1);
135 avl_insert(methodtree, mte);
136 #endif /* defined(ENABLE_JIT) */
141 /* codegen_setup ***************************************************************
143 Allocates and initialises code area, data area and references.
145 *******************************************************************************/
147 void codegen_setup(jitdata *jd)
152 /* get required compiler data */
157 cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
158 cd->mcodeend = cd->mcodebase + MCODEINITSIZE;
159 cd->mcodesize = MCODEINITSIZE;
161 /* initialize mcode variables */
163 cd->mcodeptr = cd->mcodebase;
164 cd->lastmcodeptr = cd->mcodebase;
166 #if defined(ENABLE_INTRP)
167 /* native dynamic superinstructions variables */
170 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
171 cd->ncodesize = NCODEINITSIZE;
173 /* initialize ncode variables */
175 cd->ncodeptr = cd->ncodebase;
177 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
178 cd->superstarts = NULL;
185 cd->jumpreferences = NULL;
187 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
188 cd->datareferences = NULL;
191 cd->exceptionrefs = NULL;
192 /* cd->patchrefs = list_create_dump(OFFSET(patchref, linkage)); */
193 cd->patchrefs = NULL;
195 cd->linenumberreferences = NULL;
196 cd->linenumbertablesizepos = 0;
197 cd->linenumbertablestartpos = 0;
198 cd->linenumbertab = 0;
202 cd->maxstack = m->maxstack;
204 #if defined(ENABLE_THREADS)
205 cd->threadcritcurrent.next = NULL;
206 cd->threadcritcount = 0;
211 /* codegen_close ***************************************************************
215 *******************************************************************************/
217 void codegen_close(void)
219 /* TODO: release avl tree on i386 and x86_64 */
223 /* codegen_increase ************************************************************
227 *******************************************************************************/
229 void codegen_increase(codegendata *cd)
233 /* save old mcodebase pointer */
235 oldmcodebase = cd->mcodebase;
237 /* reallocate to new, doubled memory */
239 cd->mcodebase = DMREALLOC(cd->mcodebase,
244 cd->mcodeend = cd->mcodebase + cd->mcodesize;
246 /* set new mcodeptr */
248 cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
250 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
251 /* adjust the pointer to the last patcher position */
253 if (cd->lastmcodeptr != NULL)
254 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
259 /* codegen_ncode_increase ******************************************************
263 *******************************************************************************/
265 #if defined(ENABLE_INTRP)
266 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
270 /* save old ncodebase pointer */
272 oldncodebase = cd->ncodebase;
274 /* reallocate to new, doubled memory */
276 cd->ncodebase = DMREALLOC(cd->ncodebase,
282 /* return the new ncodeptr */
284 return (cd->ncodebase + (ncodeptr - oldncodebase));
289 /* codegen_add_branch_ref ******************************************************
291 Prepends an branch to the list.
293 *******************************************************************************/
295 void codegen_add_branch_ref(codegendata *cd, basicblock *target)
299 /* calculate the mpc of the branch instruction */
301 branchmpc = cd->mcodeptr - cd->mcodebase;
303 #if defined(ENABLE_JIT)
304 /* Check if the target basicblock has already a start pc, so the
305 jump is backward and we can resolve it immediately. */
307 if ((target->mpc >= 0)
308 # if defined(ENABLE_INTRP)
309 /* The interpreter uses absolute branches, so we do branch
310 resolving after the code and data segment move. */
316 md_codegen_patch_branch(cd, branchmpc, target->mpc);
321 branchref *br = DNEW(branchref);
323 br->branchpos = branchmpc;
324 br->next = target->branchrefs;
326 target->branchrefs = br;
331 /* codegen_resolve_branchrefs **************************************************
333 Resolves and patches the branch references of a given basic block.
335 *******************************************************************************/
337 void codegen_resolve_branchrefs(codegendata *cd, basicblock *bptr)
345 targetmpc = bptr->mpc;
347 for (br = bptr->branchrefs; br != NULL; br = br->next) {
348 branchmpc = br->branchpos;
350 md_codegen_patch_branch(cd, branchmpc, targetmpc);
355 /* codegen_add_exception_ref ***************************************************
357 Prepends an exception branch to the list.
359 *******************************************************************************/
361 static void codegen_add_exception_ref(codegendata *cd, s4 reg,
362 functionptr function)
367 branchmpc = cd->mcodeptr - cd->mcodebase;
369 er = DNEW(exceptionref);
371 er->branchpos = branchmpc;
373 er->function = function;
375 er->next = cd->exceptionrefs;
377 cd->exceptionrefs = er;
381 /* codegen_add_arithmeticexception_ref *****************************************
383 Adds an ArithmeticException branch to the list.
385 *******************************************************************************/
387 void codegen_add_arithmeticexception_ref(codegendata *cd)
389 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arithmeticexception);
393 /* codegen_add_arrayindexoutofboundsexception_ref ******************************
395 Adds an ArrayIndexOutOfBoundsException branch to the list.
397 *******************************************************************************/
399 void codegen_add_arrayindexoutofboundsexception_ref(codegendata *cd, s4 reg)
401 codegen_add_exception_ref(cd, reg,
402 STACKTRACE_inline_arrayindexoutofboundsexception);
406 /* codegen_add_arraystoreexception_ref *****************************************
408 Adds an ArrayStoreException branch to the list.
410 *******************************************************************************/
412 void codegen_add_arraystoreexception_ref(codegendata *cd)
414 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arraystoreexception);
418 /* codegen_add_classcastexception_ref ******************************************
420 Adds an ClassCastException branch to the list.
422 *******************************************************************************/
424 void codegen_add_classcastexception_ref(codegendata *cd, s4 reg)
426 codegen_add_exception_ref(cd, reg, STACKTRACE_inline_classcastexception);
430 /* codegen_add_nullpointerexception_ref ****************************************
432 Adds an NullPointerException branch to the list.
434 *******************************************************************************/
436 void codegen_add_nullpointerexception_ref(codegendata *cd)
438 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_nullpointerexception);
442 /* codegen_add_fillinstacktrace_ref ********************************************
444 Adds a fillInStackTrace branch to the list.
446 *******************************************************************************/
448 void codegen_add_fillinstacktrace_ref(codegendata *cd)
450 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_fillInStackTrace);
454 /* codegen_add_patch_ref *******************************************************
456 Appends a new patcher reference to the list of patching positions.
458 *******************************************************************************/
460 void codegen_add_patch_ref(codegendata *cd, functionptr patcher, voidptr ref,
466 branchmpc = cd->mcodeptr - cd->mcodebase;
470 pr->branchpos = branchmpc;
472 pr->patcher = patcher;
475 /* list_add_first(cd->patchrefs, pr); */
476 pr->next = cd->patchrefs;
479 #if defined(ENABLE_JIT) && (defined(__ALPHA__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__X86_64__) || defined(__S390__))
480 /* Generate NOPs for opt_shownops. */
486 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
487 /* On some architectures the patcher stub call instruction might
488 be longer than the actual instruction generated. On this
489 architectures we store the last patcher call position and after
490 the basic block code generation is completed, we check the
491 range and maybe generate some nop's. */
493 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
498 /* methodtree_comparator *******************************************************
500 Comparator function used for the AVL tree of methods.
502 *******************************************************************************/
504 static s4 methodtree_comparator(const void *pc, const void *element)
506 methodtree_element *mte;
507 methodtree_element *mtepc;
509 mte = (methodtree_element *) element;
510 mtepc = (methodtree_element *) pc;
512 /* compare both startpc and endpc of pc, even if they have the same value,
513 otherwise the avl_probe sometimes thinks the element is already in the
517 /* On S390 addresses are 31 bit, and therefore are ambigue. */
518 # define ADDR_MASK(a) ((a) & 0x7FFFFFFF)
520 # define ADDR_MASK(a) (a)
523 if (ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->startpc) &&
524 ADDR_MASK((long) mtepc->startpc) <= ADDR_MASK((long) mte->endpc) &&
525 ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->endpc) &&
526 ADDR_MASK((long) mtepc->endpc) <= ADDR_MASK((long) mte->endpc)) {
529 } else if (ADDR_MASK((long) mtepc->startpc) < ADDR_MASK((long) mte->startpc)) {
540 /* codegen_insertmethod ********************************************************
542 Insert the machine code range of a method into the AVL tree of methods.
544 *******************************************************************************/
546 void codegen_insertmethod(u1 *startpc, u1 *endpc)
548 methodtree_element *mte;
550 /* allocate new method entry */
552 mte = NEW(methodtree_element);
554 mte->startpc = startpc;
557 /* this function does not return an error, but asserts for
560 avl_insert(methodtree, mte);
564 /* codegen_get_pv_from_pc ******************************************************
566 Find the PV for the given PC by searching in the AVL tree of
569 *******************************************************************************/
571 u1 *codegen_get_pv_from_pc(u1 *pc)
573 methodtree_element mtepc;
574 methodtree_element *mte;
576 /* allocation of the search structure on the stack is much faster */
581 mte = avl_find(methodtree, &mtepc);
584 /* No method was found. Let's dump a stacktrace. */
586 log_println("We received a SIGSEGV and tried to handle it, but we were");
587 log_println("unable to find a Java method at:");
589 #if SIZEOF_VOID_P == 8
590 log_println("PC=0x%016lx", pc);
592 log_println("PC=0x%08x", pc);
595 log_println("Dumping the current stacktrace:");
597 stacktrace_dump_trace(THREADOBJECT);
599 vm_abort("Exiting...");
606 /* codegen_get_pv_from_pc_nocheck **********************************************
608 Find the PV for the given PC by searching in the AVL tree of
609 methods. This method does not check the return value and is used
612 *******************************************************************************/
614 u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
616 methodtree_element mtepc;
617 methodtree_element *mte;
619 /* allocation of the search structure on the stack is much faster */
624 mte = avl_find(methodtree, &mtepc);
633 /* codegen_set_replacement_point_notrap ****************************************
635 Record the position of a non-trappable replacement point.
637 *******************************************************************************/
639 #if defined(ENABLE_REPLACEMENT)
641 void codegen_set_replacement_point_notrap(codegendata *cd, s4 type)
643 void codegen_set_replacement_point_notrap(codegendata *cd)
646 assert(cd->replacementpoint);
647 assert(cd->replacementpoint->type == type);
648 assert(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP);
650 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
652 cd->replacementpoint++;
654 #endif /* defined(ENABLE_REPLACEMENT) */
657 /* codegen_set_replacement_point ***********************************************
659 Record the position of a trappable replacement point.
661 *******************************************************************************/
663 #if defined(ENABLE_REPLACEMENT)
665 void codegen_set_replacement_point(codegendata *cd, s4 type)
667 void codegen_set_replacement_point(codegendata *cd)
670 assert(cd->replacementpoint);
671 assert(cd->replacementpoint->type == type);
672 assert(!(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP));
674 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
676 cd->replacementpoint++;
678 /* XXX assert(cd->lastmcodeptr <= cd->mcodeptr); */
680 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
682 #endif /* defined(ENABLE_REPLACEMENT) */
685 /* codegen_finish **************************************************************
687 Finishes the code generation. A new memory, large enough for both
688 data and code, is allocated and data and code are copied together
689 to their final layout, unresolved jumps are resolved, ...
691 *******************************************************************************/
693 void codegen_finish(jitdata *jd)
698 #if defined(ENABLE_INTRP)
707 /* get required compiler data */
712 /* prevent compiler warning */
714 #if defined(ENABLE_INTRP)
718 /* calculate the code length */
720 mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
722 #if defined(ENABLE_THREADS)
723 extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
728 #if defined(ENABLE_STATISTICS)
730 count_code_len += mcodelen;
731 count_data_len += cd->dseglen;
735 alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
737 #if defined(ENABLE_INTRP)
739 ncodelen = cd->ncodeptr - cd->ncodebase;
741 ncodelen = 0; /* avoid compiler warning */
745 cd->dseglen = MEMORY_ALIGN(cd->dseglen, MAX_ALIGN);
746 alignedlen = alignedmcodelen + cd->dseglen;
748 #if defined(ENABLE_INTRP)
750 alignedlen += ncodelen;
754 /* allocate new memory */
756 code->mcodelength = mcodelen + cd->dseglen;
757 code->mcode = CNEW(u1, alignedlen + extralen);
759 /* set the entrypoint of the method */
761 assert(code->entrypoint == NULL);
762 code->entrypoint = epoint = (code->mcode + cd->dseglen);
764 /* fill the data segment (code->entrypoint must already be set!) */
768 /* copy code to the new location */
770 MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
772 #if defined(ENABLE_INTRP)
773 /* relocate native dynamic superinstruction code (if any) */
776 cd->mcodebase = code->entrypoint;
779 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
781 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
783 /* flush the instruction and data caches */
785 md_cacheflush(ncodebase, ncodelen);
787 /* set some cd variables for dynamic_super_rerwite */
789 cd->ncodebase = ncodebase;
792 cd->ncodebase = NULL;
795 dynamic_super_rewrite(cd);
799 /* jump table resolving */
801 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
802 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
803 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
805 /* line number table resolving */
811 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
813 target = lr->targetmpc;
814 /* if the entry contains an mcode pointer (normal case), resolve it */
815 /* (see doc/inlining_stacktrace.txt for details) */
816 if (lr->linenumber >= -2) {
817 target += (ptrint) epoint;
819 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
820 (functionptr) target;
823 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
824 (functionptr) ((ptrint) epoint + cd->linenumbertab);
826 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
829 #if defined(ENABLE_REPLACEMENT)
830 /* replacement point resolving */
835 code->replacementstubs += (ptrint) epoint;
837 rp = code->rplpoints;
838 for (i=0; i<code->rplpointcount; ++i, ++rp) {
839 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
842 #endif /* defined(ENABLE_REPLACEMENT) */
844 /* add method into methodtree to find the entrypoint */
846 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
848 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
849 /* resolve data segment references */
851 dseg_resolve_datareferences(jd);
854 #if defined(ENABLE_THREADS)
856 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
858 codegen_critical_section_t *nt = cd->threadcrit;
860 for (i = 0; i < cd->threadcritcount; i++) {
861 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
862 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
863 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
864 critical_register_critical_section(n);
871 /* flush the instruction and data caches */
873 md_cacheflush(code->mcode, code->mcodelength);
877 /* codegen_createnativestub ****************************************************
879 Wrapper for createnativestub.
882 the codeinfo representing the stub code.
884 *******************************************************************************/
886 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
895 /* mark dump memory */
897 dumpsize = dump_size();
902 jd->cd = DNEW(codegendata);
903 jd->rd = DNEW(registerdata);
906 /* Allocate codeinfo memory from the heap as we need to keep them. */
908 jd->code = code_codeinfo_new(m); /* XXX check allocation */
910 /* get required compiler data */
914 /* set the flags for the current JIT run */
916 #if defined(ENABLE_PROFILING)
918 jd->flags |= JITDATA_FLAG_INSTRUMENT;
922 jd->flags |= JITDATA_FLAG_VERBOSECALL;
924 /* setup code generation stuff */
926 #if defined(ENABLE_JIT)
927 # if defined(ENABLE_INTRP)
935 /* create new method descriptor with additional native parameters */
938 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
940 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
941 md->paramcount * sizeof(typedesc) +
942 nativeparams * sizeof(typedesc));
944 nmd->paramcount = md->paramcount + nativeparams;
946 nmd->params = DMNEW(paramdesc, nmd->paramcount);
948 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
950 if (m->flags & ACC_STATIC)
951 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
953 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
956 #if defined(ENABLE_JIT)
957 # if defined(ENABLE_INTRP)
963 /* generate the code */
965 #if defined(ENABLE_JIT)
966 # if defined(ENABLE_INTRP)
968 code->entrypoint = intrp_createnativestub(f, jd, nmd);
971 code->entrypoint = createnativestub(f, jd, nmd);
973 code->entrypoint = intrp_createnativestub(f, jd, nmd);
976 #if defined(ENABLE_STATISTICS)
978 count_nstub_len += code->mcodelength;
982 /* disassemble native stub */
984 if (opt_shownativestub) {
985 #if defined(ENABLE_DISASSEMBLER)
986 codegen_disassemble_nativestub(m,
987 (u1 *) (ptrint) code->entrypoint,
988 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
991 /* show data segment */
993 if (opt_showddatasegment)
996 #endif /* !defined(NDEBUG) */
1000 dump_release(dumpsize);
1002 /* return native stub code */
1008 /* codegen_disassemble_nativestub **********************************************
1010 Disassembles the generated native stub.
1012 *******************************************************************************/
1014 #if defined(ENABLE_DISASSEMBLER)
1015 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
1017 printf("Native stub: ");
1018 utf_fprint_printable_ascii_classname(stdout, m->class->name);
1020 utf_fprint_printable_ascii(stdout, m->name);
1021 utf_fprint_printable_ascii(stdout, m->descriptor);
1022 printf("\n\nLength: %d\n\n", (s4) (end - start));
1024 DISASSEMBLE(start, end);
1029 /* codegen_start_native_call ***************************************************
1031 Prepares the stuff required for a native (JNI) function call:
1033 - adds a stackframe info structure to the chain, for stacktraces
1034 - prepares the local references table on the stack
1036 The layout of the native stub stackframe should look like this:
1038 +---------------------------+ <- SP (of parent Java function)
1040 +---------------------------+
1042 | stackframe info structure |
1044 +---------------------------+
1046 | local references table |
1048 +---------------------------+
1050 | arguments (if any) |
1052 +---------------------------+ <- SP (native stub)
1054 *******************************************************************************/
1056 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
1058 stackframeinfo *sfi;
1059 localref_table *lrt;
1061 /* get data structures from stack */
1063 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1064 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1065 sizeof(localref_table));
1067 /* add a stackframeinfo to the chain */
1069 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1071 #if defined(ENABLE_JAVASE)
1072 /* add current JNI local references table to this thread */
1074 lrt->capacity = LOCALREFTABLE_CAPACITY;
1076 lrt->localframes = 1;
1077 lrt->prev = LOCALREFTABLE;
1079 /* clear the references array (memset is faster the a for-loop) */
1081 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1083 LOCALREFTABLE = lrt;
1088 /* codegen_finish_native_call **************************************************
1090 Removes the stuff required for a native (JNI) function call.
1091 Additionally it checks for an exceptions and in case, get the
1092 exception object and clear the pointer.
1094 *******************************************************************************/
1096 java_objectheader *codegen_finish_native_call(u1 *datasp)
1098 stackframeinfo *sfi;
1099 stackframeinfo **psfi;
1100 localref_table *lrt;
1101 localref_table *plrt;
1103 java_objectheader *e;
1105 /* get data structures from stack */
1107 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1108 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1109 sizeof(localref_table));
1111 /* remove current stackframeinfo from chain */
1113 psfi = STACKFRAMEINFO;
1117 #if defined(ENABLE_JAVASE)
1118 /* release JNI local references tables for this thread */
1120 lrt = LOCALREFTABLE;
1122 /* release all current local frames */
1124 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1125 /* get previous frame */
1129 /* Clear all reference entries (only for tables allocated on
1132 if (localframes > 1)
1133 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1137 /* set new local references table */
1142 /* now store the previous local frames in the thread structure */
1144 LOCALREFTABLE = lrt;
1147 /* get the exception and return it */
1149 e = exceptions_get_and_clear_exception();
1155 /* removecompilerstub **********************************************************
1157 Deletes a compilerstub from memory (simply by freeing it).
1159 *******************************************************************************/
1161 void removecompilerstub(u1 *stub)
1163 /* pass size 1 to keep the intern function happy */
1165 CFREE((void *) stub, 1);
1169 /* removenativestub ************************************************************
1171 Removes a previously created native-stub from memory.
1173 *******************************************************************************/
1175 void removenativestub(u1 *stub)
1177 /* pass size 1 to keep the intern function happy */
1179 CFREE((void *) stub, 1);
1183 /* codegen_reg_of_var **********************************************************
1185 This function determines a register, to which the result of an
1186 operation should go, when it is ultimatively intended to store the
1187 result in pseudoregister v. If v is assigned to an actual
1188 register, this register will be returned. Otherwise (when v is
1189 spilled) this function returns tempregnum. If not already done,
1190 regoff and flags are set in the stack location.
1192 On ARM we have to check if a long/double variable is splitted
1193 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1194 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1195 cases. (michi 2005/07/24)
1197 *******************************************************************************/
1199 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
1203 /* Do we have to generate a conditional move? Yes, then always
1204 return the temporary register. The real register is identified
1205 during the store. */
1207 if (opcode & ICMD_CONDITION_MASK)
1211 if (!(v->flags & INMEMORY)) {
1212 #if defined(__ARM__) && defined(__ARMEL__)
1213 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
1214 return PACK_REGS(GET_LOW_REG(v->vv.regoff),
1215 GET_HIGH_REG(tempregnum));
1217 #if defined(__ARM__) && defined(__ARMEB__)
1218 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
1219 return PACK_REGS(GET_LOW_REG(tempregnum),
1220 GET_HIGH_REG(v->vv.regoff));
1222 return v->vv.regoff;
1225 #if defined(ENABLE_STATISTICS)
1227 count_spills_read++;
1233 /* codegen_reg_of_dst **********************************************************
1235 This function determines a register, to which the result of an
1236 operation should go, when it is ultimatively intended to store the
1237 result in iptr->dst.var. If dst.var is assigned to an actual
1238 register, this register will be returned. Otherwise (when it is
1239 spilled) this function returns tempregnum. If not already done,
1240 regoff and flags are set in the stack location.
1242 On ARM we have to check if a long/double variable is splitted
1243 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1244 register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
1245 cases. (michi 2005/07/24)
1247 *******************************************************************************/
1249 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1251 return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
1255 #if defined(ENABLE_THREADS)
1256 void codegen_threadcritrestart(codegendata *cd, int offset)
1258 cd->threadcritcurrent.mcoderestart = offset;
1262 void codegen_threadcritstart(codegendata *cd, int offset)
1264 cd->threadcritcurrent.mcodebegin = offset;
1268 void codegen_threadcritstop(codegendata *cd, int offset)
1270 cd->threadcritcurrent.next = cd->threadcrit;
1271 cd->threadcritcurrent.mcodeend = offset;
1272 cd->threadcrit = DNEW(codegen_critical_section_t);
1273 *(cd->threadcrit) = cd->threadcritcurrent;
1274 cd->threadcritcount++;
1280 * These are local overrides for various environment variables in Emacs.
1281 * Please do not remove this and leave it at the end of the file, where
1282 * Emacs will automagically detect them.
1283 * ---------------------------------------------------------------------
1286 * indent-tabs-mode: t
1290 * vim:noexpandtab:sw=4:ts=4: