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 7674 2007-04-05 13:27:11Z 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 #include "threads/threads-common.h"
75 #include "vm/exceptions.h"
76 #include "vm/stringlocal.h"
78 #include "vm/jit/abi.h"
79 #include "vm/jit/asmpart.h"
80 #include "vm/jit/codegen-common.h"
82 #if defined(ENABLE_DISASSEMBLER)
83 # include "vm/jit/disass.h"
86 #include "vm/jit/dseg.h"
87 #include "vm/jit/emit-common.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 # include "vmcore/statistics.h"
103 /* in this tree we store all method addresses *********************************/
105 static avl_tree *methodtree = NULL;
106 static s4 methodtree_comparator(const void *pc, const void *element);
109 /* codegen_init ****************************************************************
113 *******************************************************************************/
115 void codegen_init(void)
117 /* this tree is global, not method specific */
120 #if defined(ENABLE_JIT)
121 methodtree_element *mte;
124 methodtree = avl_create(&methodtree_comparator);
126 #if defined(ENABLE_JIT)
127 /* insert asm_vm_call_method */
129 mte = NEW(methodtree_element);
131 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
132 mte->endpc = (u1 *) (ptrint) asm_vm_call_method_end;
134 avl_insert(methodtree, mte);
135 #endif /* defined(ENABLE_JIT) */
140 /* codegen_setup ***************************************************************
142 Allocates and initialises code area, data area and references.
144 *******************************************************************************/
146 void codegen_setup(jitdata *jd)
151 /* get required compiler data */
156 /* initialize members */
160 cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
161 cd->mcodeend = cd->mcodebase + MCODEINITSIZE;
162 cd->mcodesize = MCODEINITSIZE;
164 /* initialize mcode variables */
166 cd->mcodeptr = cd->mcodebase;
167 cd->lastmcodeptr = cd->mcodebase;
169 #if defined(ENABLE_INTRP)
170 /* native dynamic superinstructions variables */
173 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
174 cd->ncodesize = NCODEINITSIZE;
176 /* initialize ncode variables */
178 cd->ncodeptr = cd->ncodebase;
180 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
181 cd->superstarts = NULL;
188 cd->jumpreferences = NULL;
190 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
191 cd->datareferences = NULL;
194 /* cd->patchrefs = list_create_dump(OFFSET(patchref, linkage)); */
195 cd->patchrefs = NULL;
196 cd->brancheslabel = list_create_dump(OFFSET(branch_label_ref_t, linkage));
198 cd->linenumberreferences = NULL;
199 cd->linenumbertablesizepos = 0;
200 cd->linenumbertablestartpos = 0;
201 cd->linenumbertab = 0;
203 cd->maxstack = m->maxstack;
205 #if defined(ENABLE_THREADS)
206 cd->threadcritcurrent.next = NULL;
207 cd->threadcritcount = 0;
212 /* codegen_reset ***************************************************************
214 Resets the codegen data structure so we can recompile the method.
216 *******************************************************************************/
218 static void codegen_reset(jitdata *jd)
224 /* get required compiler data */
229 /* reset error flag */
231 cd->flags &= ~CODEGENDATA_FLAG_ERROR;
233 /* reset some members, we reuse the code memory already allocated
234 as this should have almost the correct size */
236 cd->mcodeptr = cd->mcodebase;
237 cd->lastmcodeptr = cd->mcodebase;
242 cd->jumpreferences = NULL;
244 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
245 cd->datareferences = NULL;
248 /* cd->patchrefs = list_create_dump(OFFSET(patchref, linkage)); */
249 cd->patchrefs = NULL;
250 cd->brancheslabel = list_create_dump(OFFSET(branch_label_ref_t, linkage));
252 cd->linenumberreferences = NULL;
253 cd->linenumbertablesizepos = 0;
254 cd->linenumbertablestartpos = 0;
255 cd->linenumbertab = 0;
257 #if defined(ENABLE_THREADS)
258 cd->threadcritcurrent.next = NULL;
259 cd->threadcritcount = 0;
262 /* We need to clear the mpc and the branch references from all
263 basic blocks as they will definitely change. */
265 for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
267 bptr->branchrefs = NULL;
270 #if defined(ENABLE_REPLACEMENT)
271 code->rplpoints = NULL;
272 code->rplpointcount = 0;
273 code->regalloc = NULL;
274 code->regalloccount = 0;
275 code->globalcount = 0;
280 /* codegen_generate ************************************************************
282 Generates the code for the currently compiled method.
284 *******************************************************************************/
286 bool codegen_generate(jitdata *jd)
290 /* get required compiler data */
294 /* call the machine-dependent code generation function */
296 if (!codegen_emit(jd))
299 /* check for an error */
301 if (CODEGENDATA_HAS_FLAG_ERROR(cd)) {
302 /* check for long-branches flag, if it is set we recompile the
304 /* XXX maybe we should tag long-branches-methods for recompilation */
306 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
307 /* we have to reset the codegendata structure first */
311 /* and restart the compiler run */
313 if (!codegen_emit(jd))
317 vm_abort("codegen_generate: unknown error occurred during codegen_emit: flags=%x\n", cd->flags);
321 /* reallocate the memory and finish the code generation */
325 /* everything's ok */
331 /* codegen_close ***************************************************************
335 *******************************************************************************/
337 void codegen_close(void)
339 /* TODO: release avl tree on i386 and x86_64 */
343 /* codegen_increase ************************************************************
347 *******************************************************************************/
349 void codegen_increase(codegendata *cd)
353 /* save old mcodebase pointer */
355 oldmcodebase = cd->mcodebase;
357 /* reallocate to new, doubled memory */
359 cd->mcodebase = DMREALLOC(cd->mcodebase,
364 cd->mcodeend = cd->mcodebase + cd->mcodesize;
366 /* set new mcodeptr */
368 cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
370 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
371 /* adjust the pointer to the last patcher position */
373 if (cd->lastmcodeptr != NULL)
374 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
379 /* codegen_ncode_increase ******************************************************
383 *******************************************************************************/
385 #if defined(ENABLE_INTRP)
386 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
390 /* save old ncodebase pointer */
392 oldncodebase = cd->ncodebase;
394 /* reallocate to new, doubled memory */
396 cd->ncodebase = DMREALLOC(cd->ncodebase,
402 /* return the new ncodeptr */
404 return (cd->ncodebase + (ncodeptr - oldncodebase));
409 /* codegen_add_branch_ref ******************************************************
411 Prepends an branch to the list.
413 *******************************************************************************/
415 void codegen_add_branch_ref(codegendata *cd, basicblock *target, s4 condition, s4 reg, u4 options)
420 STATISTICS(count_branches_unresolved++);
422 /* calculate the mpc of the branch instruction */
424 branchmpc = cd->mcodeptr - cd->mcodebase;
426 br = DNEW(branchref);
428 br->branchmpc = branchmpc;
429 br->condition = condition;
431 br->options = options;
432 br->next = target->branchrefs;
434 target->branchrefs = br;
438 /* codegen_resolve_branchrefs **************************************************
440 Resolves and patches the branch references of a given basic block.
442 *******************************************************************************/
444 void codegen_resolve_branchrefs(codegendata *cd, basicblock *bptr)
449 /* Save the mcodeptr because in the branch emitting functions
450 we generate code somewhere inside already generated code,
451 but we're still in the actual code generation phase. */
453 mcodeptr = cd->mcodeptr;
455 /* just to make sure */
457 assert(bptr->mpc >= 0);
459 for (br = bptr->branchrefs; br != NULL; br = br->next) {
460 /* temporary set the mcodeptr */
462 cd->mcodeptr = cd->mcodebase + br->branchmpc;
464 /* emit_bccz and emit_branch emit the correct code, even if we
465 pass condition == BRANCH_UNCONDITIONAL or reg == -1. */
467 emit_bccz(cd, bptr, br->condition, br->reg, br->options);
470 /* restore mcodeptr */
472 cd->mcodeptr = mcodeptr;
476 /* codegen_branch_label_add ****************************************************
478 Append an branch to the label-branch list.
480 *******************************************************************************/
482 void codegen_branch_label_add(codegendata *cd, s4 label, s4 condition, s4 reg, u4 options)
485 branch_label_ref_t *br;
488 /* get the label list */
490 list = cd->brancheslabel;
492 /* calculate the current mpc */
494 mpc = cd->mcodeptr - cd->mcodebase;
496 br = DNEW(branch_label_ref_t);
500 br->condition = condition;
502 br->options = options;
504 /* add the branch to the list */
506 list_add_last_unsynced(list, br);
510 /* codegen_add_patch_ref *******************************************************
512 Appends a new patcher reference to the list of patching positions.
514 *******************************************************************************/
516 void codegen_add_patch_ref(codegendata *cd, functionptr patcher, voidptr ref,
522 branchmpc = cd->mcodeptr - cd->mcodebase;
526 pr->branchpos = branchmpc;
528 pr->patcher = patcher;
531 /* list_add_first(cd->patchrefs, pr); */
532 pr->next = cd->patchrefs;
535 /* Generate NOPs for opt_shownops. */
540 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
541 /* On some architectures the patcher stub call instruction might
542 be longer than the actual instruction generated. On this
543 architectures we store the last patcher call position and after
544 the basic block code generation is completed, we check the
545 range and maybe generate some nop's. */
547 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
552 /* methodtree_comparator *******************************************************
554 Comparator function used for the AVL tree of methods.
556 *******************************************************************************/
558 static s4 methodtree_comparator(const void *pc, const void *element)
560 methodtree_element *mte;
561 methodtree_element *mtepc;
563 mte = (methodtree_element *) element;
564 mtepc = (methodtree_element *) pc;
566 /* compare both startpc and endpc of pc, even if they have the same value,
567 otherwise the avl_probe sometimes thinks the element is already in the
571 /* On S390 addresses are 31 bit. Compare only 31 bits of value.
573 # define ADDR_MASK(a) ((a) & 0x7FFFFFFF)
575 # define ADDR_MASK(a) (a)
578 if (ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->startpc) &&
579 ADDR_MASK((long) mtepc->startpc) <= ADDR_MASK((long) mte->endpc) &&
580 ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->endpc) &&
581 ADDR_MASK((long) mtepc->endpc) <= ADDR_MASK((long) mte->endpc)) {
584 } else if (ADDR_MASK((long) mtepc->startpc) < ADDR_MASK((long) mte->startpc)) {
595 /* codegen_insertmethod ********************************************************
597 Insert the machine code range of a method into the AVL tree of methods.
599 *******************************************************************************/
601 void codegen_insertmethod(u1 *startpc, u1 *endpc)
603 methodtree_element *mte;
605 /* allocate new method entry */
607 mte = NEW(methodtree_element);
609 mte->startpc = startpc;
612 /* this function does not return an error, but asserts for
615 avl_insert(methodtree, mte);
619 /* codegen_get_pv_from_pc ******************************************************
621 Find the PV for the given PC by searching in the AVL tree of
624 *******************************************************************************/
626 u1 *codegen_get_pv_from_pc(u1 *pc)
628 methodtree_element mtepc;
629 methodtree_element *mte;
631 /* allocation of the search structure on the stack is much faster */
636 mte = avl_find(methodtree, &mtepc);
639 /* No method was found. Let's dump a stacktrace. */
641 log_println("We received a SIGSEGV and tried to handle it, but we were");
642 log_println("unable to find a Java method at:");
644 #if SIZEOF_VOID_P == 8
645 log_println("PC=0x%016lx", pc);
647 log_println("PC=0x%08x", pc);
650 log_println("Dumping the current stacktrace:");
652 #if defined(ENABLE_THREADS)
653 /* XXX michi: This should be available even without threads! */
654 threads_print_stacktrace(THREADOBJECT);
657 vm_abort("Exiting...");
664 /* codegen_get_pv_from_pc_nocheck **********************************************
666 Find the PV for the given PC by searching in the AVL tree of
667 methods. This method does not check the return value and is used
670 *******************************************************************************/
672 u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
674 methodtree_element mtepc;
675 methodtree_element *mte;
677 /* allocation of the search structure on the stack is much faster */
682 mte = avl_find(methodtree, &mtepc);
691 /* codegen_set_replacement_point_notrap ****************************************
693 Record the position of a non-trappable replacement point.
695 *******************************************************************************/
697 #if defined(ENABLE_REPLACEMENT)
699 void codegen_set_replacement_point_notrap(codegendata *cd, s4 type)
701 void codegen_set_replacement_point_notrap(codegendata *cd)
704 assert(cd->replacementpoint);
705 assert(cd->replacementpoint->type == type);
706 assert(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP);
708 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
710 cd->replacementpoint++;
712 #endif /* defined(ENABLE_REPLACEMENT) */
715 /* codegen_set_replacement_point ***********************************************
717 Record the position of a trappable replacement point.
719 *******************************************************************************/
721 #if defined(ENABLE_REPLACEMENT)
723 void codegen_set_replacement_point(codegendata *cd, s4 type)
725 void codegen_set_replacement_point(codegendata *cd)
728 assert(cd->replacementpoint);
729 assert(cd->replacementpoint->type == type);
730 assert(!(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP));
732 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
734 cd->replacementpoint++;
736 /* XXX assert(cd->lastmcodeptr <= cd->mcodeptr); */
738 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
740 #endif /* defined(ENABLE_REPLACEMENT) */
743 /* codegen_finish **************************************************************
745 Finishes the code generation. A new memory, large enough for both
746 data and code, is allocated and data and code are copied together
747 to their final layout, unresolved jumps are resolved, ...
749 *******************************************************************************/
751 void codegen_finish(jitdata *jd)
756 #if defined(ENABLE_INTRP)
765 /* get required compiler data */
770 /* prevent compiler warning */
772 #if defined(ENABLE_INTRP)
776 /* calculate the code length */
778 mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
780 #if defined(ENABLE_THREADS)
781 extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
786 #if defined(ENABLE_STATISTICS)
788 count_code_len += mcodelen;
789 count_data_len += cd->dseglen;
793 alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
795 #if defined(ENABLE_INTRP)
797 ncodelen = cd->ncodeptr - cd->ncodebase;
799 ncodelen = 0; /* avoid compiler warning */
803 cd->dseglen = MEMORY_ALIGN(cd->dseglen, MAX_ALIGN);
804 alignedlen = alignedmcodelen + cd->dseglen;
806 #if defined(ENABLE_INTRP)
808 alignedlen += ncodelen;
812 /* allocate new memory */
814 code->mcodelength = mcodelen + cd->dseglen;
815 code->mcode = CNEW(u1, alignedlen + extralen);
817 /* set the entrypoint of the method */
819 assert(code->entrypoint == NULL);
820 code->entrypoint = epoint = (code->mcode + cd->dseglen);
822 /* fill the data segment (code->entrypoint must already be set!) */
826 /* copy code to the new location */
828 MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
830 #if defined(ENABLE_INTRP)
831 /* relocate native dynamic superinstruction code (if any) */
834 cd->mcodebase = code->entrypoint;
837 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
839 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
841 /* flush the instruction and data caches */
843 md_cacheflush(ncodebase, ncodelen);
845 /* set some cd variables for dynamic_super_rerwite */
847 cd->ncodebase = ncodebase;
850 cd->ncodebase = NULL;
853 dynamic_super_rewrite(cd);
857 /* jump table resolving */
859 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
860 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
861 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
863 /* line number table resolving */
869 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
871 target = lr->targetmpc;
872 /* if the entry contains an mcode pointer (normal case), resolve it */
873 /* (see doc/inlining_stacktrace.txt for details) */
874 if (lr->linenumber >= -2) {
875 target += (ptrint) epoint;
877 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
878 (functionptr) target;
881 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
882 (functionptr) ((ptrint) epoint + cd->linenumbertab);
884 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
887 #if defined(ENABLE_REPLACEMENT)
888 /* replacement point resolving */
893 code->replacementstubs += (ptrint) epoint;
895 rp = code->rplpoints;
896 for (i=0; i<code->rplpointcount; ++i, ++rp) {
897 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
900 #endif /* defined(ENABLE_REPLACEMENT) */
902 /* add method into methodtree to find the entrypoint */
904 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
906 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
907 /* resolve data segment references */
909 dseg_resolve_datareferences(jd);
912 #if defined(ENABLE_THREADS)
914 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
916 codegen_critical_section_t *nt = cd->threadcrit;
918 for (i = 0; i < cd->threadcritcount; i++) {
919 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
920 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
921 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
922 critical_register_critical_section(n);
929 /* flush the instruction and data caches */
931 md_cacheflush(code->mcode, code->mcodelength);
935 /* codegen_createnativestub ****************************************************
937 Wrapper for createnativestub.
940 the codeinfo representing the stub code.
942 *******************************************************************************/
944 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
953 /* mark dump memory */
955 dumpsize = dump_size();
960 jd->cd = DNEW(codegendata);
961 jd->rd = DNEW(registerdata);
964 /* Allocate codeinfo memory from the heap as we need to keep them. */
966 jd->code = code_codeinfo_new(m); /* XXX check allocation */
968 /* get required compiler data */
972 /* set the flags for the current JIT run */
974 #if defined(ENABLE_PROFILING)
976 jd->flags |= JITDATA_FLAG_INSTRUMENT;
980 jd->flags |= JITDATA_FLAG_VERBOSECALL;
982 /* setup code generation stuff */
984 #if defined(ENABLE_JIT)
985 # if defined(ENABLE_INTRP)
993 /* create new method descriptor with additional native parameters */
996 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
998 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
999 md->paramcount * sizeof(typedesc) +
1000 nativeparams * sizeof(typedesc));
1002 nmd->paramcount = md->paramcount + nativeparams;
1004 nmd->params = DMNEW(paramdesc, nmd->paramcount);
1006 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
1008 if (m->flags & ACC_STATIC)
1009 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
1011 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
1014 #if defined(ENABLE_JIT)
1015 # if defined(ENABLE_INTRP)
1018 /* pre-allocate the arguments for the native ABI */
1020 md_param_alloc_native(nmd);
1023 /* generate the code */
1025 #if defined(ENABLE_JIT)
1026 # if defined(ENABLE_INTRP)
1028 code->entrypoint = intrp_createnativestub(f, jd, nmd);
1031 code->entrypoint = createnativestub(f, jd, nmd);
1033 code->entrypoint = intrp_createnativestub(f, jd, nmd);
1036 #if defined(ENABLE_STATISTICS)
1038 count_nstub_len += code->mcodelength;
1041 #if !defined(NDEBUG)
1042 /* disassemble native stub */
1044 if (opt_shownativestub) {
1045 #if defined(ENABLE_DISASSEMBLER)
1046 codegen_disassemble_nativestub(m,
1047 (u1 *) (ptrint) code->entrypoint,
1048 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
1051 /* show data segment */
1053 if (opt_showddatasegment)
1056 #endif /* !defined(NDEBUG) */
1058 /* release memory */
1060 dump_release(dumpsize);
1062 /* return native stub code */
1068 /* codegen_disassemble_nativestub **********************************************
1070 Disassembles the generated native stub.
1072 *******************************************************************************/
1074 #if defined(ENABLE_DISASSEMBLER)
1075 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
1077 printf("Native stub: ");
1078 utf_fprint_printable_ascii_classname(stdout, m->class->name);
1080 utf_fprint_printable_ascii(stdout, m->name);
1081 utf_fprint_printable_ascii(stdout, m->descriptor);
1082 printf("\n\nLength: %d\n\n", (s4) (end - start));
1084 DISASSEMBLE(start, end);
1089 /* codegen_start_native_call ***************************************************
1091 Prepares the stuff required for a native (JNI) function call:
1093 - adds a stackframe info structure to the chain, for stacktraces
1094 - prepares the local references table on the stack
1096 The layout of the native stub stackframe should look like this:
1098 +---------------------------+ <- SP (of parent Java function)
1100 +---------------------------+
1102 | stackframe info structure |
1104 +---------------------------+
1106 | local references table |
1108 +---------------------------+
1110 | arguments (if any) |
1112 +---------------------------+ <- SP (native stub)
1114 *******************************************************************************/
1116 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
1118 stackframeinfo *sfi;
1119 localref_table *lrt;
1121 /* get data structures from stack */
1123 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1124 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1125 sizeof(localref_table));
1127 /* add a stackframeinfo to the chain */
1129 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1131 #if defined(ENABLE_JAVASE)
1132 /* add current JNI local references table to this thread */
1134 lrt->capacity = LOCALREFTABLE_CAPACITY;
1136 lrt->localframes = 1;
1137 lrt->prev = LOCALREFTABLE;
1139 /* clear the references array (memset is faster the a for-loop) */
1141 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1143 LOCALREFTABLE = lrt;
1146 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1147 /* set the native world flag */
1149 THREADOBJECT->flags |= THREAD_FLAG_IN_NATIVE;
1154 /* codegen_finish_native_call **************************************************
1156 Removes the stuff required for a native (JNI) function call.
1157 Additionally it checks for an exceptions and in case, get the
1158 exception object and clear the pointer.
1160 *******************************************************************************/
1162 java_objectheader *codegen_finish_native_call(u1 *datasp)
1164 stackframeinfo *sfi;
1165 stackframeinfo **psfi;
1166 localref_table *lrt;
1167 localref_table *plrt;
1169 java_objectheader *e;
1171 /* get data structures from stack */
1173 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1174 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1175 sizeof(localref_table));
1177 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1178 /* clear the native world flag */
1180 THREADOBJECT->flags &= ~THREAD_FLAG_IN_NATIVE;
1183 /* remove current stackframeinfo from chain */
1185 psfi = &STACKFRAMEINFO;
1189 #if defined(ENABLE_JAVASE)
1190 /* release JNI local references tables for this thread */
1192 lrt = LOCALREFTABLE;
1194 /* release all current local frames */
1196 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1197 /* get previous frame */
1201 /* Clear all reference entries (only for tables allocated on
1204 if (localframes > 1)
1205 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1209 /* set new local references table */
1214 /* now store the previous local frames in the thread structure */
1216 LOCALREFTABLE = lrt;
1219 /* get the exception and return it */
1221 e = exceptions_get_and_clear_exception();
1227 /* removecompilerstub **********************************************************
1229 Deletes a compilerstub from memory (simply by freeing it).
1231 *******************************************************************************/
1233 void removecompilerstub(u1 *stub)
1235 /* pass size 1 to keep the intern function happy */
1237 CFREE((void *) stub, 1);
1241 /* removenativestub ************************************************************
1243 Removes a previously created native-stub from memory.
1245 *******************************************************************************/
1247 void removenativestub(u1 *stub)
1249 /* pass size 1 to keep the intern function happy */
1251 CFREE((void *) stub, 1);
1255 /* codegen_reg_of_var **********************************************************
1257 This function determines a register, to which the result of an
1258 operation should go, when it is ultimatively intended to store the
1259 result in pseudoregister v. If v is assigned to an actual
1260 register, this register will be returned. Otherwise (when v is
1261 spilled) this function returns tempregnum. If not already done,
1262 regoff and flags are set in the stack location.
1264 On ARM we have to check if a long/double variable is splitted
1265 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1266 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1267 cases. (michi 2005/07/24)
1269 *******************************************************************************/
1271 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
1275 /* Do we have to generate a conditional move? Yes, then always
1276 return the temporary register. The real register is identified
1277 during the store. */
1279 if (opcode & ICMD_CONDITION_MASK)
1283 if (!(v->flags & INMEMORY)) {
1284 #if defined(__ARM__) && defined(__ARMEL__)
1285 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
1286 return PACK_REGS(GET_LOW_REG(v->vv.regoff),
1287 GET_HIGH_REG(tempregnum));
1289 #if defined(__ARM__) && defined(__ARMEB__)
1290 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
1291 return PACK_REGS(GET_LOW_REG(tempregnum),
1292 GET_HIGH_REG(v->vv.regoff));
1294 return v->vv.regoff;
1297 #if defined(ENABLE_STATISTICS)
1299 count_spills_read++;
1305 /* codegen_reg_of_dst **********************************************************
1307 This function determines a register, to which the result of an
1308 operation should go, when it is ultimatively intended to store the
1309 result in iptr->dst.var. If dst.var is assigned to an actual
1310 register, this register will be returned. Otherwise (when it is
1311 spilled) this function returns tempregnum. If not already done,
1312 regoff and flags are set in the stack location.
1314 On ARM we have to check if a long/double variable is splitted
1315 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1316 register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
1317 cases. (michi 2005/07/24)
1319 *******************************************************************************/
1321 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1323 return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
1327 #if defined(ENABLE_THREADS)
1328 void codegen_threadcritrestart(codegendata *cd, int offset)
1330 cd->threadcritcurrent.mcoderestart = offset;
1334 void codegen_threadcritstart(codegendata *cd, int offset)
1336 cd->threadcritcurrent.mcodebegin = offset;
1340 void codegen_threadcritstop(codegendata *cd, int offset)
1342 cd->threadcritcurrent.next = cd->threadcrit;
1343 cd->threadcritcurrent.mcodeend = offset;
1344 cd->threadcrit = DNEW(codegen_critical_section_t);
1345 *(cd->threadcrit) = cd->threadcritcurrent;
1346 cd->threadcritcount++;
1352 * These are local overrides for various environment variables in Emacs.
1353 * Please do not remove this and leave it at the end of the file, where
1354 * Emacs will automagically detect them.
1355 * ---------------------------------------------------------------------
1358 * indent-tabs-mode: t
1362 * vim:noexpandtab:sw=4:ts=4: