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 7601 2007-03-28 23:02:50Z 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/emit-common.h"
90 #include "vm/jit/jit.h"
91 #include "vm/jit/md.h"
92 #include "vm/jit/replace.h"
93 #include "vm/jit/stacktrace.h"
95 #if defined(ENABLE_INTRP)
96 #include "vm/jit/intrp/intrp.h"
99 #include "vmcore/method.h"
100 #include "vmcore/options.h"
102 # 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_vm_call_method_end;
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 /* initialize members */
162 cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
163 cd->mcodeend = cd->mcodebase + MCODEINITSIZE;
164 cd->mcodesize = MCODEINITSIZE;
166 /* initialize mcode variables */
168 cd->mcodeptr = cd->mcodebase;
169 cd->lastmcodeptr = cd->mcodebase;
171 #if defined(ENABLE_INTRP)
172 /* native dynamic superinstructions variables */
175 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
176 cd->ncodesize = NCODEINITSIZE;
178 /* initialize ncode variables */
180 cd->ncodeptr = cd->ncodebase;
182 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
183 cd->superstarts = NULL;
190 cd->jumpreferences = NULL;
192 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
193 cd->datareferences = NULL;
196 /* cd->patchrefs = list_create_dump(OFFSET(patchref, linkage)); */
197 cd->patchrefs = NULL;
198 cd->brancheslabel = list_create_dump(OFFSET(branch_label_ref_t, linkage));
200 cd->linenumberreferences = NULL;
201 cd->linenumbertablesizepos = 0;
202 cd->linenumbertablestartpos = 0;
203 cd->linenumbertab = 0;
205 cd->maxstack = m->maxstack;
207 #if defined(ENABLE_THREADS)
208 cd->threadcritcurrent.next = NULL;
209 cd->threadcritcount = 0;
214 /* codegen_reset ***************************************************************
216 Resets the codegen data structure so we can recompile the method.
218 *******************************************************************************/
220 static void codegen_reset(jitdata *jd)
226 /* get required compiler data */
231 /* reset error flag */
233 cd->flags &= ~CODEGENDATA_FLAG_ERROR;
235 /* reset some members, we reuse the code memory already allocated
236 as this should have almost the correct size */
238 cd->mcodeptr = cd->mcodebase;
239 cd->lastmcodeptr = cd->mcodebase;
244 cd->jumpreferences = NULL;
246 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
247 cd->datareferences = NULL;
250 /* cd->patchrefs = list_create_dump(OFFSET(patchref, linkage)); */
251 cd->patchrefs = NULL;
252 cd->brancheslabel = list_create_dump(OFFSET(branch_label_ref_t, linkage));
254 cd->linenumberreferences = NULL;
255 cd->linenumbertablesizepos = 0;
256 cd->linenumbertablestartpos = 0;
257 cd->linenumbertab = 0;
259 #if defined(ENABLE_THREADS)
260 cd->threadcritcurrent.next = NULL;
261 cd->threadcritcount = 0;
264 /* We need to clear the mpc and the branch references from all
265 basic blocks as they will definitely change. */
267 for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
269 bptr->branchrefs = NULL;
272 #if defined(ENABLE_REPLACEMENT)
273 code->rplpoints = NULL;
274 code->rplpointcount = 0;
275 code->regalloc = NULL;
276 code->regalloccount = 0;
277 code->globalcount = 0;
282 /* codegen_generate ************************************************************
284 Generates the code for the currently compiled method.
286 *******************************************************************************/
288 bool codegen_generate(jitdata *jd)
292 /* get required compiler data */
296 /* call the machine-dependent code generation function */
298 if (!codegen_emit(jd))
301 /* check for an error */
303 if (CODEGENDATA_HAS_FLAG_ERROR(cd)) {
304 /* check for long-branches flag, if it is set we recompile the
306 /* XXX maybe we should tag long-branches-methods for recompilation */
308 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
309 /* we have to reset the codegendata structure first */
313 /* and restart the compiler run */
315 if (!codegen_emit(jd))
319 vm_abort("codegen_generate: unknown error occurred during codegen_emit: flags=%x\n", cd->flags);
323 /* reallocate the memory and finish the code generation */
327 /* everything's ok */
333 /* codegen_close ***************************************************************
337 *******************************************************************************/
339 void codegen_close(void)
341 /* TODO: release avl tree on i386 and x86_64 */
345 /* codegen_increase ************************************************************
349 *******************************************************************************/
351 void codegen_increase(codegendata *cd)
355 /* save old mcodebase pointer */
357 oldmcodebase = cd->mcodebase;
359 /* reallocate to new, doubled memory */
361 cd->mcodebase = DMREALLOC(cd->mcodebase,
366 cd->mcodeend = cd->mcodebase + cd->mcodesize;
368 /* set new mcodeptr */
370 cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
372 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
373 /* adjust the pointer to the last patcher position */
375 if (cd->lastmcodeptr != NULL)
376 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
381 /* codegen_ncode_increase ******************************************************
385 *******************************************************************************/
387 #if defined(ENABLE_INTRP)
388 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
392 /* save old ncodebase pointer */
394 oldncodebase = cd->ncodebase;
396 /* reallocate to new, doubled memory */
398 cd->ncodebase = DMREALLOC(cd->ncodebase,
404 /* return the new ncodeptr */
406 return (cd->ncodebase + (ncodeptr - oldncodebase));
411 /* codegen_add_branch_ref ******************************************************
413 Prepends an branch to the list.
415 *******************************************************************************/
417 void codegen_add_branch_ref(codegendata *cd, basicblock *target, s4 condition, s4 reg, u4 options)
422 STATISTICS(count_branches_unresolved++);
424 /* calculate the mpc of the branch instruction */
426 branchmpc = cd->mcodeptr - cd->mcodebase;
428 br = DNEW(branchref);
430 br->branchmpc = branchmpc;
431 br->condition = condition;
433 br->options = options;
434 br->next = target->branchrefs;
436 target->branchrefs = br;
440 /* codegen_resolve_branchrefs **************************************************
442 Resolves and patches the branch references of a given basic block.
444 *******************************************************************************/
446 void codegen_resolve_branchrefs(codegendata *cd, basicblock *bptr)
451 /* Save the mcodeptr because in the branch emitting functions
452 we generate code somewhere inside already generated code,
453 but we're still in the actual code generation phase. */
455 mcodeptr = cd->mcodeptr;
457 /* just to make sure */
459 assert(bptr->mpc >= 0);
461 for (br = bptr->branchrefs; br != NULL; br = br->next) {
462 /* temporary set the mcodeptr */
464 cd->mcodeptr = cd->mcodebase + br->branchmpc;
466 /* emit_bccz and emit_branch emit the correct code, even if we
467 pass condition == BRANCH_UNCONDITIONAL or reg == -1. */
469 emit_bccz(cd, bptr, br->condition, br->reg, br->options);
472 /* restore mcodeptr */
474 cd->mcodeptr = mcodeptr;
478 /* codegen_branch_label_add ****************************************************
480 Append an branch to the label-branch list.
482 *******************************************************************************/
484 void codegen_branch_label_add(codegendata *cd, s4 label, s4 condition, s4 reg, u4 options)
487 branch_label_ref_t *br;
490 /* get the label list */
492 list = cd->brancheslabel;
494 /* calculate the current mpc */
496 mpc = cd->mcodeptr - cd->mcodebase;
498 br = DNEW(branch_label_ref_t);
502 br->condition = condition;
504 br->options = options;
506 /* add the branch to the list */
508 list_add_last_unsynced(list, br);
512 /* codegen_add_patch_ref *******************************************************
514 Appends a new patcher reference to the list of patching positions.
516 *******************************************************************************/
518 void codegen_add_patch_ref(codegendata *cd, functionptr patcher, voidptr ref,
524 branchmpc = cd->mcodeptr - cd->mcodebase;
528 pr->branchpos = branchmpc;
530 pr->patcher = patcher;
533 /* list_add_first(cd->patchrefs, pr); */
534 pr->next = cd->patchrefs;
537 /* Generate NOPs for opt_shownops. */
542 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
543 /* On some architectures the patcher stub call instruction might
544 be longer than the actual instruction generated. On this
545 architectures we store the last patcher call position and after
546 the basic block code generation is completed, we check the
547 range and maybe generate some nop's. */
549 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
554 /* methodtree_comparator *******************************************************
556 Comparator function used for the AVL tree of methods.
558 *******************************************************************************/
560 static s4 methodtree_comparator(const void *pc, const void *element)
562 methodtree_element *mte;
563 methodtree_element *mtepc;
565 mte = (methodtree_element *) element;
566 mtepc = (methodtree_element *) pc;
568 /* compare both startpc and endpc of pc, even if they have the same value,
569 otherwise the avl_probe sometimes thinks the element is already in the
573 /* On S390 addresses are 31 bit. Compare only 31 bits of value.
575 # define ADDR_MASK(a) ((a) & 0x7FFFFFFF)
577 # define ADDR_MASK(a) (a)
580 if (ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->startpc) &&
581 ADDR_MASK((long) mtepc->startpc) <= ADDR_MASK((long) mte->endpc) &&
582 ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->endpc) &&
583 ADDR_MASK((long) mtepc->endpc) <= ADDR_MASK((long) mte->endpc)) {
586 } else if (ADDR_MASK((long) mtepc->startpc) < ADDR_MASK((long) mte->startpc)) {
597 /* codegen_insertmethod ********************************************************
599 Insert the machine code range of a method into the AVL tree of methods.
601 *******************************************************************************/
603 void codegen_insertmethod(u1 *startpc, u1 *endpc)
605 methodtree_element *mte;
607 /* allocate new method entry */
609 mte = NEW(methodtree_element);
611 mte->startpc = startpc;
614 /* this function does not return an error, but asserts for
617 avl_insert(methodtree, mte);
621 /* codegen_get_pv_from_pc ******************************************************
623 Find the PV for the given PC by searching in the AVL tree of
626 *******************************************************************************/
628 u1 *codegen_get_pv_from_pc(u1 *pc)
630 methodtree_element mtepc;
631 methodtree_element *mte;
633 /* allocation of the search structure on the stack is much faster */
638 mte = avl_find(methodtree, &mtepc);
641 /* No method was found. Let's dump a stacktrace. */
643 log_println("We received a SIGSEGV and tried to handle it, but we were");
644 log_println("unable to find a Java method at:");
646 #if SIZEOF_VOID_P == 8
647 log_println("PC=0x%016lx", pc);
649 log_println("PC=0x%08x", pc);
652 log_println("Dumping the current stacktrace:");
654 stacktrace_dump_trace(THREADOBJECT);
656 vm_abort("Exiting...");
663 /* codegen_get_pv_from_pc_nocheck **********************************************
665 Find the PV for the given PC by searching in the AVL tree of
666 methods. This method does not check the return value and is used
669 *******************************************************************************/
671 u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
673 methodtree_element mtepc;
674 methodtree_element *mte;
676 /* allocation of the search structure on the stack is much faster */
681 mte = avl_find(methodtree, &mtepc);
690 /* codegen_set_replacement_point_notrap ****************************************
692 Record the position of a non-trappable replacement point.
694 *******************************************************************************/
696 #if defined(ENABLE_REPLACEMENT)
698 void codegen_set_replacement_point_notrap(codegendata *cd, s4 type)
700 void codegen_set_replacement_point_notrap(codegendata *cd)
703 assert(cd->replacementpoint);
704 assert(cd->replacementpoint->type == type);
705 assert(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP);
707 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
709 cd->replacementpoint++;
711 #endif /* defined(ENABLE_REPLACEMENT) */
714 /* codegen_set_replacement_point ***********************************************
716 Record the position of a trappable replacement point.
718 *******************************************************************************/
720 #if defined(ENABLE_REPLACEMENT)
722 void codegen_set_replacement_point(codegendata *cd, s4 type)
724 void codegen_set_replacement_point(codegendata *cd)
727 assert(cd->replacementpoint);
728 assert(cd->replacementpoint->type == type);
729 assert(!(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP));
731 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
733 cd->replacementpoint++;
735 /* XXX assert(cd->lastmcodeptr <= cd->mcodeptr); */
737 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
739 #endif /* defined(ENABLE_REPLACEMENT) */
742 /* codegen_finish **************************************************************
744 Finishes the code generation. A new memory, large enough for both
745 data and code, is allocated and data and code are copied together
746 to their final layout, unresolved jumps are resolved, ...
748 *******************************************************************************/
750 void codegen_finish(jitdata *jd)
755 #if defined(ENABLE_INTRP)
764 /* get required compiler data */
769 /* prevent compiler warning */
771 #if defined(ENABLE_INTRP)
775 /* calculate the code length */
777 mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
779 #if defined(ENABLE_THREADS)
780 extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
785 #if defined(ENABLE_STATISTICS)
787 count_code_len += mcodelen;
788 count_data_len += cd->dseglen;
792 alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
794 #if defined(ENABLE_INTRP)
796 ncodelen = cd->ncodeptr - cd->ncodebase;
798 ncodelen = 0; /* avoid compiler warning */
802 cd->dseglen = MEMORY_ALIGN(cd->dseglen, MAX_ALIGN);
803 alignedlen = alignedmcodelen + cd->dseglen;
805 #if defined(ENABLE_INTRP)
807 alignedlen += ncodelen;
811 /* allocate new memory */
813 code->mcodelength = mcodelen + cd->dseglen;
814 code->mcode = CNEW(u1, alignedlen + extralen);
816 /* set the entrypoint of the method */
818 assert(code->entrypoint == NULL);
819 code->entrypoint = epoint = (code->mcode + cd->dseglen);
821 /* fill the data segment (code->entrypoint must already be set!) */
825 /* copy code to the new location */
827 MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
829 #if defined(ENABLE_INTRP)
830 /* relocate native dynamic superinstruction code (if any) */
833 cd->mcodebase = code->entrypoint;
836 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
838 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
840 /* flush the instruction and data caches */
842 md_cacheflush(ncodebase, ncodelen);
844 /* set some cd variables for dynamic_super_rerwite */
846 cd->ncodebase = ncodebase;
849 cd->ncodebase = NULL;
852 dynamic_super_rewrite(cd);
856 /* jump table resolving */
858 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
859 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
860 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
862 /* line number table resolving */
868 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
870 target = lr->targetmpc;
871 /* if the entry contains an mcode pointer (normal case), resolve it */
872 /* (see doc/inlining_stacktrace.txt for details) */
873 if (lr->linenumber >= -2) {
874 target += (ptrint) epoint;
876 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
877 (functionptr) target;
880 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
881 (functionptr) ((ptrint) epoint + cd->linenumbertab);
883 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
886 #if defined(ENABLE_REPLACEMENT)
887 /* replacement point resolving */
892 code->replacementstubs += (ptrint) epoint;
894 rp = code->rplpoints;
895 for (i=0; i<code->rplpointcount; ++i, ++rp) {
896 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
899 #endif /* defined(ENABLE_REPLACEMENT) */
901 /* add method into methodtree to find the entrypoint */
903 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
905 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
906 /* resolve data segment references */
908 dseg_resolve_datareferences(jd);
911 #if defined(ENABLE_THREADS)
913 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
915 codegen_critical_section_t *nt = cd->threadcrit;
917 for (i = 0; i < cd->threadcritcount; i++) {
918 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
919 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
920 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
921 critical_register_critical_section(n);
928 /* flush the instruction and data caches */
930 md_cacheflush(code->mcode, code->mcodelength);
934 /* codegen_createnativestub ****************************************************
936 Wrapper for createnativestub.
939 the codeinfo representing the stub code.
941 *******************************************************************************/
943 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
952 /* mark dump memory */
954 dumpsize = dump_size();
959 jd->cd = DNEW(codegendata);
960 jd->rd = DNEW(registerdata);
963 /* Allocate codeinfo memory from the heap as we need to keep them. */
965 jd->code = code_codeinfo_new(m); /* XXX check allocation */
967 /* get required compiler data */
971 /* set the flags for the current JIT run */
973 #if defined(ENABLE_PROFILING)
975 jd->flags |= JITDATA_FLAG_INSTRUMENT;
979 jd->flags |= JITDATA_FLAG_VERBOSECALL;
981 /* setup code generation stuff */
983 #if defined(ENABLE_JIT)
984 # if defined(ENABLE_INTRP)
992 /* create new method descriptor with additional native parameters */
995 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
997 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
998 md->paramcount * sizeof(typedesc) +
999 nativeparams * sizeof(typedesc));
1001 nmd->paramcount = md->paramcount + nativeparams;
1003 nmd->params = DMNEW(paramdesc, nmd->paramcount);
1005 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
1007 if (m->flags & ACC_STATIC)
1008 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
1010 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
1013 #if defined(ENABLE_JIT)
1014 # if defined(ENABLE_INTRP)
1017 /* pre-allocate the arguments for the native ABI */
1019 md_param_alloc_native(nmd);
1022 /* generate the code */
1024 #if defined(ENABLE_JIT)
1025 # if defined(ENABLE_INTRP)
1027 code->entrypoint = intrp_createnativestub(f, jd, nmd);
1030 code->entrypoint = createnativestub(f, jd, nmd);
1032 code->entrypoint = intrp_createnativestub(f, jd, nmd);
1035 #if defined(ENABLE_STATISTICS)
1037 count_nstub_len += code->mcodelength;
1040 #if !defined(NDEBUG)
1041 /* disassemble native stub */
1043 if (opt_shownativestub) {
1044 #if defined(ENABLE_DISASSEMBLER)
1045 codegen_disassemble_nativestub(m,
1046 (u1 *) (ptrint) code->entrypoint,
1047 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
1050 /* show data segment */
1052 if (opt_showddatasegment)
1055 #endif /* !defined(NDEBUG) */
1057 /* release memory */
1059 dump_release(dumpsize);
1061 /* return native stub code */
1067 /* codegen_disassemble_nativestub **********************************************
1069 Disassembles the generated native stub.
1071 *******************************************************************************/
1073 #if defined(ENABLE_DISASSEMBLER)
1074 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
1076 printf("Native stub: ");
1077 utf_fprint_printable_ascii_classname(stdout, m->class->name);
1079 utf_fprint_printable_ascii(stdout, m->name);
1080 utf_fprint_printable_ascii(stdout, m->descriptor);
1081 printf("\n\nLength: %d\n\n", (s4) (end - start));
1083 DISASSEMBLE(start, end);
1088 /* codegen_start_native_call ***************************************************
1090 Prepares the stuff required for a native (JNI) function call:
1092 - adds a stackframe info structure to the chain, for stacktraces
1093 - prepares the local references table on the stack
1095 The layout of the native stub stackframe should look like this:
1097 +---------------------------+ <- SP (of parent Java function)
1099 +---------------------------+
1101 | stackframe info structure |
1103 +---------------------------+
1105 | local references table |
1107 +---------------------------+
1109 | arguments (if any) |
1111 +---------------------------+ <- SP (native stub)
1113 *******************************************************************************/
1115 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
1117 stackframeinfo *sfi;
1118 localref_table *lrt;
1120 /* get data structures from stack */
1122 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1123 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1124 sizeof(localref_table));
1126 /* add a stackframeinfo to the chain */
1128 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1130 #if defined(ENABLE_JAVASE)
1131 /* add current JNI local references table to this thread */
1133 lrt->capacity = LOCALREFTABLE_CAPACITY;
1135 lrt->localframes = 1;
1136 lrt->prev = LOCALREFTABLE;
1138 /* clear the references array (memset is faster the a for-loop) */
1140 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1142 LOCALREFTABLE = lrt;
1145 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1146 /* set the native world flag */
1148 THREADOBJECT->flags |= THREAD_FLAG_IN_NATIVE;
1153 /* codegen_finish_native_call **************************************************
1155 Removes the stuff required for a native (JNI) function call.
1156 Additionally it checks for an exceptions and in case, get the
1157 exception object and clear the pointer.
1159 *******************************************************************************/
1161 java_objectheader *codegen_finish_native_call(u1 *datasp)
1163 stackframeinfo *sfi;
1164 stackframeinfo **psfi;
1165 localref_table *lrt;
1166 localref_table *plrt;
1168 java_objectheader *e;
1170 /* get data structures from stack */
1172 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1173 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1174 sizeof(localref_table));
1176 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1177 /* clear the native world flag */
1179 THREADOBJECT->flags &= ~THREAD_FLAG_IN_NATIVE;
1182 /* remove current stackframeinfo from chain */
1184 psfi = STACKFRAMEINFO;
1188 #if defined(ENABLE_JAVASE)
1189 /* release JNI local references tables for this thread */
1191 lrt = LOCALREFTABLE;
1193 /* release all current local frames */
1195 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1196 /* get previous frame */
1200 /* Clear all reference entries (only for tables allocated on
1203 if (localframes > 1)
1204 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1208 /* set new local references table */
1213 /* now store the previous local frames in the thread structure */
1215 LOCALREFTABLE = lrt;
1218 /* get the exception and return it */
1220 e = exceptions_get_and_clear_exception();
1226 /* removecompilerstub **********************************************************
1228 Deletes a compilerstub from memory (simply by freeing it).
1230 *******************************************************************************/
1232 void removecompilerstub(u1 *stub)
1234 /* pass size 1 to keep the intern function happy */
1236 CFREE((void *) stub, 1);
1240 /* removenativestub ************************************************************
1242 Removes a previously created native-stub from memory.
1244 *******************************************************************************/
1246 void removenativestub(u1 *stub)
1248 /* pass size 1 to keep the intern function happy */
1250 CFREE((void *) stub, 1);
1254 /* codegen_reg_of_var **********************************************************
1256 This function determines a register, to which the result of an
1257 operation should go, when it is ultimatively intended to store the
1258 result in pseudoregister v. If v is assigned to an actual
1259 register, this register will be returned. Otherwise (when v is
1260 spilled) this function returns tempregnum. If not already done,
1261 regoff and flags are set in the stack location.
1263 On ARM we have to check if a long/double variable is splitted
1264 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1265 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1266 cases. (michi 2005/07/24)
1268 *******************************************************************************/
1270 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
1274 /* Do we have to generate a conditional move? Yes, then always
1275 return the temporary register. The real register is identified
1276 during the store. */
1278 if (opcode & ICMD_CONDITION_MASK)
1282 if (!(v->flags & INMEMORY)) {
1283 #if defined(__ARM__) && defined(__ARMEL__)
1284 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
1285 return PACK_REGS(GET_LOW_REG(v->vv.regoff),
1286 GET_HIGH_REG(tempregnum));
1288 #if defined(__ARM__) && defined(__ARMEB__)
1289 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
1290 return PACK_REGS(GET_LOW_REG(tempregnum),
1291 GET_HIGH_REG(v->vv.regoff));
1293 return v->vv.regoff;
1296 #if defined(ENABLE_STATISTICS)
1298 count_spills_read++;
1304 /* codegen_reg_of_dst **********************************************************
1306 This function determines a register, to which the result of an
1307 operation should go, when it is ultimatively intended to store the
1308 result in iptr->dst.var. If dst.var is assigned to an actual
1309 register, this register will be returned. Otherwise (when it is
1310 spilled) this function returns tempregnum. If not already done,
1311 regoff and flags are set in the stack location.
1313 On ARM we have to check if a long/double variable is splitted
1314 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1315 register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
1316 cases. (michi 2005/07/24)
1318 *******************************************************************************/
1320 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1322 return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
1326 #if defined(ENABLE_THREADS)
1327 void codegen_threadcritrestart(codegendata *cd, int offset)
1329 cd->threadcritcurrent.mcoderestart = offset;
1333 void codegen_threadcritstart(codegendata *cd, int offset)
1335 cd->threadcritcurrent.mcodebegin = offset;
1339 void codegen_threadcritstop(codegendata *cd, int offset)
1341 cd->threadcritcurrent.next = cd->threadcrit;
1342 cd->threadcritcurrent.mcodeend = offset;
1343 cd->threadcrit = DNEW(codegen_critical_section_t);
1344 *(cd->threadcrit) = cd->threadcritcurrent;
1345 cd->threadcritcount++;
1351 * These are local overrides for various environment variables in Emacs.
1352 * Please do not remove this and leave it at the end of the file, where
1353 * Emacs will automagically detect them.
1354 * ---------------------------------------------------------------------
1357 * indent-tabs-mode: t
1361 * vim:noexpandtab:sw=4:ts=4: