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 7688 2007-04-12 09:05:12Z 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
307 log_message_method("Re-generating code: ", jd->m);
310 /* XXX maybe we should tag long-branches-methods for recompilation */
312 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
313 /* we have to reset the codegendata structure first */
317 /* and restart the compiler run */
319 if (!codegen_emit(jd))
323 vm_abort("codegen_generate: unknown error occurred during codegen_emit: flags=%x\n", cd->flags);
328 log_message_method("Re-generating code done: ", jd->m);
332 /* reallocate the memory and finish the code generation */
336 /* everything's ok */
342 /* codegen_close ***************************************************************
346 *******************************************************************************/
348 void codegen_close(void)
350 /* TODO: release avl tree on i386 and x86_64 */
354 /* codegen_increase ************************************************************
358 *******************************************************************************/
360 void codegen_increase(codegendata *cd)
364 /* save old mcodebase pointer */
366 oldmcodebase = cd->mcodebase;
368 /* reallocate to new, doubled memory */
370 cd->mcodebase = DMREALLOC(cd->mcodebase,
375 cd->mcodeend = cd->mcodebase + cd->mcodesize;
377 /* set new mcodeptr */
379 cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
381 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
382 /* adjust the pointer to the last patcher position */
384 if (cd->lastmcodeptr != NULL)
385 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
390 /* codegen_ncode_increase ******************************************************
394 *******************************************************************************/
396 #if defined(ENABLE_INTRP)
397 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
401 /* save old ncodebase pointer */
403 oldncodebase = cd->ncodebase;
405 /* reallocate to new, doubled memory */
407 cd->ncodebase = DMREALLOC(cd->ncodebase,
413 /* return the new ncodeptr */
415 return (cd->ncodebase + (ncodeptr - oldncodebase));
420 /* codegen_add_branch_ref ******************************************************
422 Prepends an branch to the list.
424 *******************************************************************************/
426 void codegen_add_branch_ref(codegendata *cd, basicblock *target, s4 condition, s4 reg, u4 options)
431 STATISTICS(count_branches_unresolved++);
433 /* calculate the mpc of the branch instruction */
435 branchmpc = cd->mcodeptr - cd->mcodebase;
437 br = DNEW(branchref);
439 br->branchmpc = branchmpc;
440 br->condition = condition;
442 br->options = options;
443 br->next = target->branchrefs;
445 target->branchrefs = br;
449 /* codegen_resolve_branchrefs **************************************************
451 Resolves and patches the branch references of a given basic block.
453 *******************************************************************************/
455 void codegen_resolve_branchrefs(codegendata *cd, basicblock *bptr)
460 /* Save the mcodeptr because in the branch emitting functions
461 we generate code somewhere inside already generated code,
462 but we're still in the actual code generation phase. */
464 mcodeptr = cd->mcodeptr;
466 /* just to make sure */
468 assert(bptr->mpc >= 0);
470 for (br = bptr->branchrefs; br != NULL; br = br->next) {
471 /* temporary set the mcodeptr */
473 cd->mcodeptr = cd->mcodebase + br->branchmpc;
475 /* emit_bccz and emit_branch emit the correct code, even if we
476 pass condition == BRANCH_UNCONDITIONAL or reg == -1. */
478 emit_bccz(cd, bptr, br->condition, br->reg, br->options);
481 /* restore mcodeptr */
483 cd->mcodeptr = mcodeptr;
487 /* codegen_branch_label_add ****************************************************
489 Append an branch to the label-branch list.
491 *******************************************************************************/
493 void codegen_branch_label_add(codegendata *cd, s4 label, s4 condition, s4 reg, u4 options)
496 branch_label_ref_t *br;
499 /* get the label list */
501 list = cd->brancheslabel;
503 /* calculate the current mpc */
505 mpc = cd->mcodeptr - cd->mcodebase;
507 br = DNEW(branch_label_ref_t);
511 br->condition = condition;
513 br->options = options;
515 /* add the branch to the list */
517 list_add_last_unsynced(list, br);
521 /* codegen_add_patch_ref *******************************************************
523 Appends a new patcher reference to the list of patching positions.
525 *******************************************************************************/
527 void codegen_add_patch_ref(codegendata *cd, functionptr patcher, voidptr ref,
533 branchmpc = cd->mcodeptr - cd->mcodebase;
537 pr->branchpos = branchmpc;
539 pr->patcher = patcher;
542 /* list_add_first(cd->patchrefs, pr); */
543 pr->next = cd->patchrefs;
546 /* Generate NOPs for opt_shownops. */
551 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
552 /* On some architectures the patcher stub call instruction might
553 be longer than the actual instruction generated. On this
554 architectures we store the last patcher call position and after
555 the basic block code generation is completed, we check the
556 range and maybe generate some nop's. */
558 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
563 /* methodtree_comparator *******************************************************
565 Comparator function used for the AVL tree of methods.
567 *******************************************************************************/
569 static s4 methodtree_comparator(const void *pc, const void *element)
571 methodtree_element *mte;
572 methodtree_element *mtepc;
574 mte = (methodtree_element *) element;
575 mtepc = (methodtree_element *) pc;
577 /* compare both startpc and endpc of pc, even if they have the same value,
578 otherwise the avl_probe sometimes thinks the element is already in the
582 /* On S390 addresses are 31 bit. Compare only 31 bits of value.
584 # define ADDR_MASK(a) ((a) & 0x7FFFFFFF)
586 # define ADDR_MASK(a) (a)
589 if (ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->startpc) &&
590 ADDR_MASK((long) mtepc->startpc) <= ADDR_MASK((long) mte->endpc) &&
591 ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->endpc) &&
592 ADDR_MASK((long) mtepc->endpc) <= ADDR_MASK((long) mte->endpc)) {
595 } else if (ADDR_MASK((long) mtepc->startpc) < ADDR_MASK((long) mte->startpc)) {
606 /* codegen_insertmethod ********************************************************
608 Insert the machine code range of a method into the AVL tree of methods.
610 *******************************************************************************/
612 void codegen_insertmethod(u1 *startpc, u1 *endpc)
614 methodtree_element *mte;
616 /* allocate new method entry */
618 mte = NEW(methodtree_element);
620 mte->startpc = startpc;
623 /* this function does not return an error, but asserts for
626 avl_insert(methodtree, mte);
630 /* codegen_get_pv_from_pc ******************************************************
632 Find the PV for the given PC by searching in the AVL tree of
635 *******************************************************************************/
637 u1 *codegen_get_pv_from_pc(u1 *pc)
639 methodtree_element mtepc;
640 methodtree_element *mte;
642 /* allocation of the search structure on the stack is much faster */
647 mte = avl_find(methodtree, &mtepc);
650 /* No method was found. Let's dump a stacktrace. */
652 log_println("We received a SIGSEGV and tried to handle it, but we were");
653 log_println("unable to find a Java method at:");
655 #if SIZEOF_VOID_P == 8
656 log_println("PC=0x%016lx", pc);
658 log_println("PC=0x%08x", pc);
661 log_println("Dumping the current stacktrace:");
663 #if defined(ENABLE_THREADS)
664 /* XXX michi: This should be available even without threads! */
665 threads_print_stacktrace(THREADOBJECT);
668 vm_abort("Exiting...");
675 /* codegen_get_pv_from_pc_nocheck **********************************************
677 Find the PV for the given PC by searching in the AVL tree of
678 methods. This method does not check the return value and is used
681 *******************************************************************************/
683 u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
685 methodtree_element mtepc;
686 methodtree_element *mte;
688 /* allocation of the search structure on the stack is much faster */
693 mte = avl_find(methodtree, &mtepc);
702 /* codegen_set_replacement_point_notrap ****************************************
704 Record the position of a non-trappable replacement point.
706 *******************************************************************************/
708 #if defined(ENABLE_REPLACEMENT)
710 void codegen_set_replacement_point_notrap(codegendata *cd, s4 type)
712 void codegen_set_replacement_point_notrap(codegendata *cd)
715 assert(cd->replacementpoint);
716 assert(cd->replacementpoint->type == type);
717 assert(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP);
719 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
721 cd->replacementpoint++;
723 #endif /* defined(ENABLE_REPLACEMENT) */
726 /* codegen_set_replacement_point ***********************************************
728 Record the position of a trappable replacement point.
730 *******************************************************************************/
732 #if defined(ENABLE_REPLACEMENT)
734 void codegen_set_replacement_point(codegendata *cd, s4 type)
736 void codegen_set_replacement_point(codegendata *cd)
739 assert(cd->replacementpoint);
740 assert(cd->replacementpoint->type == type);
741 assert(!(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP));
743 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
745 cd->replacementpoint++;
747 /* XXX assert(cd->lastmcodeptr <= cd->mcodeptr); */
749 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
751 #endif /* defined(ENABLE_REPLACEMENT) */
754 /* codegen_finish **************************************************************
756 Finishes the code generation. A new memory, large enough for both
757 data and code, is allocated and data and code are copied together
758 to their final layout, unresolved jumps are resolved, ...
760 *******************************************************************************/
762 void codegen_finish(jitdata *jd)
767 #if defined(ENABLE_INTRP)
776 /* get required compiler data */
781 /* prevent compiler warning */
783 #if defined(ENABLE_INTRP)
787 /* calculate the code length */
789 mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
791 #if defined(ENABLE_THREADS)
792 extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
797 #if defined(ENABLE_STATISTICS)
799 count_code_len += mcodelen;
800 count_data_len += cd->dseglen;
804 alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
806 #if defined(ENABLE_INTRP)
808 ncodelen = cd->ncodeptr - cd->ncodebase;
810 ncodelen = 0; /* avoid compiler warning */
814 cd->dseglen = MEMORY_ALIGN(cd->dseglen, MAX_ALIGN);
815 alignedlen = alignedmcodelen + cd->dseglen;
817 #if defined(ENABLE_INTRP)
819 alignedlen += ncodelen;
823 /* allocate new memory */
825 code->mcodelength = mcodelen + cd->dseglen;
826 code->mcode = CNEW(u1, alignedlen + extralen);
828 /* set the entrypoint of the method */
830 assert(code->entrypoint == NULL);
831 code->entrypoint = epoint = (code->mcode + cd->dseglen);
833 /* fill the data segment (code->entrypoint must already be set!) */
837 /* copy code to the new location */
839 MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
841 #if defined(ENABLE_INTRP)
842 /* relocate native dynamic superinstruction code (if any) */
845 cd->mcodebase = code->entrypoint;
848 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
850 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
852 /* flush the instruction and data caches */
854 md_cacheflush(ncodebase, ncodelen);
856 /* set some cd variables for dynamic_super_rerwite */
858 cd->ncodebase = ncodebase;
861 cd->ncodebase = NULL;
864 dynamic_super_rewrite(cd);
868 /* jump table resolving */
870 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
871 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
872 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
874 /* line number table resolving */
880 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
882 target = lr->targetmpc;
883 /* if the entry contains an mcode pointer (normal case), resolve it */
884 /* (see doc/inlining_stacktrace.txt for details) */
885 if (lr->linenumber >= -2) {
886 target += (ptrint) epoint;
888 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
889 (functionptr) target;
892 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
893 (functionptr) ((ptrint) epoint + cd->linenumbertab);
895 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
898 #if defined(ENABLE_REPLACEMENT)
899 /* replacement point resolving */
904 code->replacementstubs += (ptrint) epoint;
906 rp = code->rplpoints;
907 for (i=0; i<code->rplpointcount; ++i, ++rp) {
908 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
911 #endif /* defined(ENABLE_REPLACEMENT) */
913 /* add method into methodtree to find the entrypoint */
915 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
917 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
918 /* resolve data segment references */
920 dseg_resolve_datareferences(jd);
923 #if defined(ENABLE_THREADS)
925 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
927 codegen_critical_section_t *nt = cd->threadcrit;
929 for (i = 0; i < cd->threadcritcount; i++) {
930 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
931 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
932 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
933 critical_register_critical_section(n);
940 /* flush the instruction and data caches */
942 md_cacheflush(code->mcode, code->mcodelength);
946 /* codegen_createnativestub ****************************************************
948 Wrapper for createnativestub.
951 the codeinfo representing the stub code.
953 *******************************************************************************/
955 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
964 /* mark dump memory */
966 dumpsize = dump_size();
971 jd->cd = DNEW(codegendata);
972 jd->rd = DNEW(registerdata);
975 /* Allocate codeinfo memory from the heap as we need to keep them. */
977 jd->code = code_codeinfo_new(m); /* XXX check allocation */
979 /* get required compiler data */
983 /* set the flags for the current JIT run */
985 #if defined(ENABLE_PROFILING)
987 jd->flags |= JITDATA_FLAG_INSTRUMENT;
991 jd->flags |= JITDATA_FLAG_VERBOSECALL;
993 /* setup code generation stuff */
995 #if defined(ENABLE_JIT)
996 # if defined(ENABLE_INTRP)
1004 /* create new method descriptor with additional native parameters */
1007 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
1009 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
1010 md->paramcount * sizeof(typedesc) +
1011 nativeparams * sizeof(typedesc));
1013 nmd->paramcount = md->paramcount + nativeparams;
1015 nmd->params = DMNEW(paramdesc, nmd->paramcount);
1017 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
1019 if (m->flags & ACC_STATIC)
1020 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
1022 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
1025 #if defined(ENABLE_JIT)
1026 # if defined(ENABLE_INTRP)
1029 /* pre-allocate the arguments for the native ABI */
1031 md_param_alloc_native(nmd);
1034 /* generate the code */
1036 #if defined(ENABLE_JIT)
1037 # if defined(ENABLE_INTRP)
1039 code->entrypoint = intrp_createnativestub(f, jd, nmd);
1042 code->entrypoint = createnativestub(f, jd, nmd);
1044 code->entrypoint = intrp_createnativestub(f, jd, nmd);
1047 #if defined(ENABLE_STATISTICS)
1049 count_nstub_len += code->mcodelength;
1052 #if !defined(NDEBUG)
1053 /* disassemble native stub */
1055 if (opt_shownativestub) {
1056 #if defined(ENABLE_DISASSEMBLER)
1057 codegen_disassemble_nativestub(m,
1058 (u1 *) (ptrint) code->entrypoint,
1059 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
1062 /* show data segment */
1064 if (opt_showddatasegment)
1067 #endif /* !defined(NDEBUG) */
1069 /* release memory */
1071 dump_release(dumpsize);
1073 /* return native stub code */
1079 /* codegen_disassemble_nativestub **********************************************
1081 Disassembles the generated native stub.
1083 *******************************************************************************/
1085 #if defined(ENABLE_DISASSEMBLER)
1086 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
1088 printf("Native stub: ");
1089 utf_fprint_printable_ascii_classname(stdout, m->class->name);
1091 utf_fprint_printable_ascii(stdout, m->name);
1092 utf_fprint_printable_ascii(stdout, m->descriptor);
1093 printf("\n\nLength: %d\n\n", (s4) (end - start));
1095 DISASSEMBLE(start, end);
1100 /* codegen_start_native_call ***************************************************
1102 Prepares the stuff required for a native (JNI) function call:
1104 - adds a stackframe info structure to the chain, for stacktraces
1105 - prepares the local references table on the stack
1107 The layout of the native stub stackframe should look like this:
1109 +---------------------------+ <- SP (of parent Java function)
1111 +---------------------------+
1113 | stackframe info structure |
1115 +---------------------------+
1117 | local references table |
1119 +---------------------------+
1121 | arguments (if any) |
1123 +---------------------------+ <- SP (native stub)
1125 *******************************************************************************/
1127 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
1129 stackframeinfo *sfi;
1130 localref_table *lrt;
1132 /* get data structures from stack */
1134 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1135 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1136 sizeof(localref_table));
1138 /* add a stackframeinfo to the chain */
1140 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1142 #if defined(ENABLE_JAVASE)
1143 /* add current JNI local references table to this thread */
1145 lrt->capacity = LOCALREFTABLE_CAPACITY;
1147 lrt->localframes = 1;
1148 lrt->prev = LOCALREFTABLE;
1150 /* clear the references array (memset is faster the a for-loop) */
1152 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1154 LOCALREFTABLE = lrt;
1157 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1158 /* set the native world flag */
1160 THREADOBJECT->flags |= THREAD_FLAG_IN_NATIVE;
1165 /* codegen_finish_native_call **************************************************
1167 Removes the stuff required for a native (JNI) function call.
1168 Additionally it checks for an exceptions and in case, get the
1169 exception object and clear the pointer.
1171 *******************************************************************************/
1173 java_objectheader *codegen_finish_native_call(u1 *datasp)
1175 stackframeinfo *sfi;
1176 stackframeinfo **psfi;
1177 localref_table *lrt;
1178 localref_table *plrt;
1180 java_objectheader *e;
1182 /* get data structures from stack */
1184 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1185 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1186 sizeof(localref_table));
1188 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1189 /* clear the native world flag */
1191 THREADOBJECT->flags &= ~THREAD_FLAG_IN_NATIVE;
1194 /* remove current stackframeinfo from chain */
1196 psfi = &STACKFRAMEINFO;
1200 #if defined(ENABLE_JAVASE)
1201 /* release JNI local references tables for this thread */
1203 lrt = LOCALREFTABLE;
1205 /* release all current local frames */
1207 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1208 /* get previous frame */
1212 /* Clear all reference entries (only for tables allocated on
1215 if (localframes > 1)
1216 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1220 /* set new local references table */
1225 /* now store the previous local frames in the thread structure */
1227 LOCALREFTABLE = lrt;
1230 /* get the exception and return it */
1232 e = exceptions_get_and_clear_exception();
1238 /* removecompilerstub **********************************************************
1240 Deletes a compilerstub from memory (simply by freeing it).
1242 *******************************************************************************/
1244 void removecompilerstub(u1 *stub)
1246 /* pass size 1 to keep the intern function happy */
1248 CFREE((void *) stub, 1);
1252 /* removenativestub ************************************************************
1254 Removes a previously created native-stub from memory.
1256 *******************************************************************************/
1258 void removenativestub(u1 *stub)
1260 /* pass size 1 to keep the intern function happy */
1262 CFREE((void *) stub, 1);
1266 /* codegen_reg_of_var **********************************************************
1268 This function determines a register, to which the result of an
1269 operation should go, when it is ultimatively intended to store the
1270 result in pseudoregister v. If v is assigned to an actual
1271 register, this register will be returned. Otherwise (when v is
1272 spilled) this function returns tempregnum. If not already done,
1273 regoff and flags are set in the stack location.
1275 On ARM we have to check if a long/double variable is splitted
1276 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1277 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1278 cases. (michi 2005/07/24)
1280 *******************************************************************************/
1282 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
1286 /* Do we have to generate a conditional move? Yes, then always
1287 return the temporary register. The real register is identified
1288 during the store. */
1290 if (opcode & ICMD_CONDITION_MASK)
1294 if (!(v->flags & INMEMORY)) {
1295 #if defined(__ARM__) && defined(__ARMEL__)
1296 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
1297 return PACK_REGS(GET_LOW_REG(v->vv.regoff),
1298 GET_HIGH_REG(tempregnum));
1300 #if defined(__ARM__) && defined(__ARMEB__)
1301 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
1302 return PACK_REGS(GET_LOW_REG(tempregnum),
1303 GET_HIGH_REG(v->vv.regoff));
1305 return v->vv.regoff;
1308 #if defined(ENABLE_STATISTICS)
1310 count_spills_read++;
1316 /* codegen_reg_of_dst **********************************************************
1318 This function determines a register, to which the result of an
1319 operation should go, when it is ultimatively intended to store the
1320 result in iptr->dst.var. If dst.var is assigned to an actual
1321 register, this register will be returned. Otherwise (when it is
1322 spilled) this function returns tempregnum. If not already done,
1323 regoff and flags are set in the stack location.
1325 On ARM we have to check if a long/double variable is splitted
1326 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1327 register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
1328 cases. (michi 2005/07/24)
1330 *******************************************************************************/
1332 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1334 return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
1338 #if defined(ENABLE_THREADS)
1339 void codegen_threadcritrestart(codegendata *cd, int offset)
1341 cd->threadcritcurrent.mcoderestart = offset;
1345 void codegen_threadcritstart(codegendata *cd, int offset)
1347 cd->threadcritcurrent.mcodebegin = offset;
1351 void codegen_threadcritstop(codegendata *cd, int offset)
1353 cd->threadcritcurrent.next = cd->threadcrit;
1354 cd->threadcritcurrent.mcodeend = offset;
1355 cd->threadcrit = DNEW(codegen_critical_section_t);
1356 *(cd->threadcrit) = cd->threadcritcurrent;
1357 cd->threadcritcount++;
1363 * These are local overrides for various environment variables in Emacs.
1364 * Please do not remove this and leave it at the end of the file, where
1365 * Emacs will automagically detect them.
1366 * ---------------------------------------------------------------------
1369 * indent-tabs-mode: t
1373 * vim:noexpandtab:sw=4:ts=4: