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 7783 2007-04-20 13:28:27Z twisti $
54 #if defined(ENABLE_JIT)
55 /* this is required PATCHER_CALL_SIZE */
60 /* this is required for REG_SPLIT */
64 #include "mm/memory.h"
66 #include "toolbox/avl.h"
67 #include "toolbox/list.h"
68 #include "toolbox/logging.h"
70 #include "native/jni.h"
71 #include "native/native.h"
73 #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 #if defined(ENABLE_THREADS)
204 cd->threadcritcurrent.next = NULL;
205 cd->threadcritcount = 0;
210 /* codegen_reset ***************************************************************
212 Resets the codegen data structure so we can recompile the method.
214 *******************************************************************************/
216 static void codegen_reset(jitdata *jd)
222 /* get required compiler data */
227 /* reset error flag */
229 cd->flags &= ~CODEGENDATA_FLAG_ERROR;
231 /* reset some members, we reuse the code memory already allocated
232 as this should have almost the correct size */
234 cd->mcodeptr = cd->mcodebase;
235 cd->lastmcodeptr = cd->mcodebase;
240 cd->jumpreferences = NULL;
242 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
243 cd->datareferences = NULL;
246 /* cd->patchrefs = list_create_dump(OFFSET(patchref, linkage)); */
247 cd->patchrefs = NULL;
248 cd->brancheslabel = list_create_dump(OFFSET(branch_label_ref_t, linkage));
250 cd->linenumberreferences = NULL;
251 cd->linenumbertablesizepos = 0;
252 cd->linenumbertablestartpos = 0;
253 cd->linenumbertab = 0;
255 #if defined(ENABLE_THREADS)
256 cd->threadcritcurrent.next = NULL;
257 cd->threadcritcount = 0;
260 /* We need to clear the mpc and the branch references from all
261 basic blocks as they will definitely change. */
263 for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
265 bptr->branchrefs = NULL;
268 #if defined(ENABLE_REPLACEMENT)
269 code->rplpoints = NULL;
270 code->rplpointcount = 0;
271 code->regalloc = NULL;
272 code->regalloccount = 0;
273 code->globalcount = 0;
278 /* codegen_generate ************************************************************
280 Generates the code for the currently compiled method.
282 *******************************************************************************/
284 bool codegen_generate(jitdata *jd)
288 /* get required compiler data */
292 /* call the machine-dependent code generation function */
294 if (!codegen_emit(jd))
297 /* check for an error */
299 if (CODEGENDATA_HAS_FLAG_ERROR(cd)) {
300 /* check for long-branches flag, if it is set we recompile the
305 log_message_method("Re-generating code: ", jd->m);
308 /* XXX maybe we should tag long-branches-methods for recompilation */
310 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
311 /* we have to reset the codegendata structure first */
315 /* and restart the compiler run */
317 if (!codegen_emit(jd))
321 vm_abort("codegen_generate: unknown error occurred during codegen_emit: flags=%x\n", cd->flags);
326 log_message_method("Re-generating code done: ", jd->m);
330 /* reallocate the memory and finish the code generation */
334 /* everything's ok */
340 /* codegen_close ***************************************************************
344 *******************************************************************************/
346 void codegen_close(void)
348 /* TODO: release avl tree on i386 and x86_64 */
352 /* codegen_increase ************************************************************
356 *******************************************************************************/
358 void codegen_increase(codegendata *cd)
362 /* save old mcodebase pointer */
364 oldmcodebase = cd->mcodebase;
366 /* reallocate to new, doubled memory */
368 cd->mcodebase = DMREALLOC(cd->mcodebase,
373 cd->mcodeend = cd->mcodebase + cd->mcodesize;
375 /* set new mcodeptr */
377 cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
379 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
380 /* adjust the pointer to the last patcher position */
382 if (cd->lastmcodeptr != NULL)
383 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
388 /* codegen_ncode_increase ******************************************************
392 *******************************************************************************/
394 #if defined(ENABLE_INTRP)
395 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
399 /* save old ncodebase pointer */
401 oldncodebase = cd->ncodebase;
403 /* reallocate to new, doubled memory */
405 cd->ncodebase = DMREALLOC(cd->ncodebase,
411 /* return the new ncodeptr */
413 return (cd->ncodebase + (ncodeptr - oldncodebase));
418 /* codegen_add_branch_ref ******************************************************
420 Prepends an branch to the list.
422 *******************************************************************************/
424 void codegen_add_branch_ref(codegendata *cd, basicblock *target, s4 condition, s4 reg, u4 options)
429 STATISTICS(count_branches_unresolved++);
431 /* calculate the mpc of the branch instruction */
433 branchmpc = cd->mcodeptr - cd->mcodebase;
435 br = DNEW(branchref);
437 br->branchmpc = branchmpc;
438 br->condition = condition;
440 br->options = options;
441 br->next = target->branchrefs;
443 target->branchrefs = br;
447 /* codegen_resolve_branchrefs **************************************************
449 Resolves and patches the branch references of a given basic block.
451 *******************************************************************************/
453 void codegen_resolve_branchrefs(codegendata *cd, basicblock *bptr)
458 /* Save the mcodeptr because in the branch emitting functions
459 we generate code somewhere inside already generated code,
460 but we're still in the actual code generation phase. */
462 mcodeptr = cd->mcodeptr;
464 /* just to make sure */
466 assert(bptr->mpc >= 0);
468 for (br = bptr->branchrefs; br != NULL; br = br->next) {
469 /* temporary set the mcodeptr */
471 cd->mcodeptr = cd->mcodebase + br->branchmpc;
473 /* emit_bccz and emit_branch emit the correct code, even if we
474 pass condition == BRANCH_UNCONDITIONAL or reg == -1. */
476 emit_bccz(cd, bptr, br->condition, br->reg, br->options);
479 /* restore mcodeptr */
481 cd->mcodeptr = mcodeptr;
485 /* codegen_branch_label_add ****************************************************
487 Append an branch to the label-branch list.
489 *******************************************************************************/
491 void codegen_branch_label_add(codegendata *cd, s4 label, s4 condition, s4 reg, u4 options)
494 branch_label_ref_t *br;
497 /* get the label list */
499 list = cd->brancheslabel;
501 /* calculate the current mpc */
503 mpc = cd->mcodeptr - cd->mcodebase;
505 br = DNEW(branch_label_ref_t);
509 br->condition = condition;
511 br->options = options;
513 /* add the branch to the list */
515 list_add_last_unsynced(list, br);
519 /* codegen_add_patch_ref *******************************************************
521 Appends a new patcher reference to the list of patching positions.
523 *******************************************************************************/
525 void codegen_add_patch_ref(codegendata *cd, functionptr patcher, voidptr ref,
531 branchmpc = cd->mcodeptr - cd->mcodebase;
535 pr->branchpos = branchmpc;
537 pr->patcher = patcher;
540 /* list_add_first(cd->patchrefs, pr); */
541 pr->next = cd->patchrefs;
544 /* Generate NOPs for opt_shownops. */
549 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
550 /* On some architectures the patcher stub call instruction might
551 be longer than the actual instruction generated. On this
552 architectures we store the last patcher call position and after
553 the basic block code generation is completed, we check the
554 range and maybe generate some nop's. */
556 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
561 /* methodtree_comparator *******************************************************
563 Comparator function used for the AVL tree of methods.
565 *******************************************************************************/
567 static s4 methodtree_comparator(const void *pc, const void *element)
569 methodtree_element *mte;
570 methodtree_element *mtepc;
572 mte = (methodtree_element *) element;
573 mtepc = (methodtree_element *) pc;
575 /* compare both startpc and endpc of pc, even if they have the same value,
576 otherwise the avl_probe sometimes thinks the element is already in the
580 /* On S390 addresses are 31 bit. Compare only 31 bits of value.
582 # define ADDR_MASK(a) ((a) & 0x7FFFFFFF)
584 # define ADDR_MASK(a) (a)
587 if (ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->startpc) &&
588 ADDR_MASK((long) mtepc->startpc) <= ADDR_MASK((long) mte->endpc) &&
589 ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->endpc) &&
590 ADDR_MASK((long) mtepc->endpc) <= ADDR_MASK((long) mte->endpc)) {
593 } else if (ADDR_MASK((long) mtepc->startpc) < ADDR_MASK((long) mte->startpc)) {
604 /* codegen_insertmethod ********************************************************
606 Insert the machine code range of a method into the AVL tree of methods.
608 *******************************************************************************/
610 void codegen_insertmethod(u1 *startpc, u1 *endpc)
612 methodtree_element *mte;
614 /* allocate new method entry */
616 mte = NEW(methodtree_element);
618 mte->startpc = startpc;
621 /* this function does not return an error, but asserts for
624 avl_insert(methodtree, mte);
628 /* codegen_get_pv_from_pc ******************************************************
630 Find the PV for the given PC by searching in the AVL tree of
633 *******************************************************************************/
635 u1 *codegen_get_pv_from_pc(u1 *pc)
637 methodtree_element mtepc;
638 methodtree_element *mte;
640 /* allocation of the search structure on the stack is much faster */
645 mte = avl_find(methodtree, &mtepc);
648 /* No method was found. Let's dump a stacktrace. */
650 log_println("We received a SIGSEGV and tried to handle it, but we were");
651 log_println("unable to find a Java method at:");
653 #if SIZEOF_VOID_P == 8
654 log_println("PC=0x%016lx", pc);
656 log_println("PC=0x%08x", pc);
659 log_println("Dumping the current stacktrace:");
661 #if defined(ENABLE_THREADS)
662 /* XXX michi: This should be available even without threads! */
663 threads_print_stacktrace();
666 vm_abort("Exiting...");
673 /* codegen_get_pv_from_pc_nocheck **********************************************
675 Find the PV for the given PC by searching in the AVL tree of
676 methods. This method does not check the return value and is used
679 *******************************************************************************/
681 u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
683 methodtree_element mtepc;
684 methodtree_element *mte;
686 /* allocation of the search structure on the stack is much faster */
691 mte = avl_find(methodtree, &mtepc);
700 /* codegen_set_replacement_point_notrap ****************************************
702 Record the position of a non-trappable replacement point.
704 *******************************************************************************/
706 #if defined(ENABLE_REPLACEMENT)
708 void codegen_set_replacement_point_notrap(codegendata *cd, s4 type)
710 void codegen_set_replacement_point_notrap(codegendata *cd)
713 assert(cd->replacementpoint);
714 assert(cd->replacementpoint->type == type);
715 assert(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP);
717 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
719 cd->replacementpoint++;
721 #endif /* defined(ENABLE_REPLACEMENT) */
724 /* codegen_set_replacement_point ***********************************************
726 Record the position of a trappable replacement point.
728 *******************************************************************************/
730 #if defined(ENABLE_REPLACEMENT)
732 void codegen_set_replacement_point(codegendata *cd, s4 type)
734 void codegen_set_replacement_point(codegendata *cd)
737 assert(cd->replacementpoint);
738 assert(cd->replacementpoint->type == type);
739 assert(!(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP));
741 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
743 cd->replacementpoint++;
745 /* XXX assert(cd->lastmcodeptr <= cd->mcodeptr); */
747 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
749 #endif /* defined(ENABLE_REPLACEMENT) */
752 /* codegen_finish **************************************************************
754 Finishes the code generation. A new memory, large enough for both
755 data and code, is allocated and data and code are copied together
756 to their final layout, unresolved jumps are resolved, ...
758 *******************************************************************************/
760 void codegen_finish(jitdata *jd)
765 #if defined(ENABLE_INTRP)
774 /* get required compiler data */
779 /* prevent compiler warning */
781 #if defined(ENABLE_INTRP)
785 /* calculate the code length */
787 mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
789 #if defined(ENABLE_THREADS)
790 extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
795 #if defined(ENABLE_STATISTICS)
797 count_code_len += mcodelen;
798 count_data_len += cd->dseglen;
802 alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
804 #if defined(ENABLE_INTRP)
806 ncodelen = cd->ncodeptr - cd->ncodebase;
808 ncodelen = 0; /* avoid compiler warning */
812 cd->dseglen = MEMORY_ALIGN(cd->dseglen, MAX_ALIGN);
813 alignedlen = alignedmcodelen + cd->dseglen;
815 #if defined(ENABLE_INTRP)
817 alignedlen += ncodelen;
821 /* allocate new memory */
823 code->mcodelength = mcodelen + cd->dseglen;
824 code->mcode = CNEW(u1, alignedlen + extralen);
826 /* set the entrypoint of the method */
828 assert(code->entrypoint == NULL);
829 code->entrypoint = epoint = (code->mcode + cd->dseglen);
831 /* fill the data segment (code->entrypoint must already be set!) */
835 /* copy code to the new location */
837 MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
839 #if defined(ENABLE_INTRP)
840 /* relocate native dynamic superinstruction code (if any) */
843 cd->mcodebase = code->entrypoint;
846 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
848 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
850 /* flush the instruction and data caches */
852 md_cacheflush(ncodebase, ncodelen);
854 /* set some cd variables for dynamic_super_rerwite */
856 cd->ncodebase = ncodebase;
859 cd->ncodebase = NULL;
862 dynamic_super_rewrite(cd);
866 /* jump table resolving */
868 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
869 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
870 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
872 /* line number table resolving */
878 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
880 target = lr->targetmpc;
881 /* if the entry contains an mcode pointer (normal case), resolve it */
882 /* (see doc/inlining_stacktrace.txt for details) */
883 if (lr->linenumber >= -2) {
884 target += (ptrint) epoint;
886 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
887 (functionptr) target;
890 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
891 (functionptr) ((ptrint) epoint + cd->linenumbertab);
893 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
896 #if defined(ENABLE_REPLACEMENT)
897 /* replacement point resolving */
902 code->replacementstubs += (ptrint) epoint;
904 rp = code->rplpoints;
905 for (i=0; i<code->rplpointcount; ++i, ++rp) {
906 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
909 #endif /* defined(ENABLE_REPLACEMENT) */
911 /* add method into methodtree to find the entrypoint */
913 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
915 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
916 /* resolve data segment references */
918 dseg_resolve_datareferences(jd);
921 #if defined(ENABLE_THREADS)
923 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
925 codegen_critical_section_t *nt = cd->threadcrit;
927 for (i = 0; i < cd->threadcritcount; i++) {
928 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
929 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
930 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
931 critical_register_critical_section(n);
938 /* flush the instruction and data caches */
940 md_cacheflush(code->mcode, code->mcodelength);
944 /* codegen_generate_stub_compiler **********************************************
946 Wrapper for codegen_emit_stub_compiler.
949 pointer to the compiler stub code.
951 *******************************************************************************/
953 u1 *codegen_generate_stub_compiler(methodinfo *m)
957 ptrint *d; /* pointer to data memory */
958 u1 *c; /* pointer to code memory */
961 /* mark dump memory */
963 dumpsize = dump_size();
965 /* allocate required data structures */
970 jd->cd = DNEW(codegendata);
973 /* get required compiler data */
977 /* allocate code memory */
979 c = CNEW(u1, 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE);
981 /* set pointers correctly */
987 c = c + 3 * SIZEOF_VOID_P;
990 /* NOTE: The codeinfo pointer is actually a pointer to the
991 methodinfo (this fakes a codeinfo structure). */
993 d[0] = (ptrint) asm_call_jit_compiler;
995 d[2] = (ptrint) &d[1]; /* fake code->m */
997 /* call the emit function */
999 codegen_emit_stub_compiler(jd);
1001 #if defined(ENABLE_STATISTICS)
1003 count_cstub_len += 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE;
1008 md_cacheflush(cd->mcodebase, 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE);
1010 /* release dump memory */
1012 dump_release(dumpsize);
1014 /* return native stub code */
1020 /* codegen_generate_stub_native ************************************************
1022 Wrapper for codegen_emit_stub_native.
1025 the codeinfo representing the stub code.
1027 *******************************************************************************/
1029 codeinfo *codegen_generate_stub_native(methodinfo *m, functionptr f)
1038 /* mark dump memory */
1040 dumpsize = dump_size();
1045 jd->cd = DNEW(codegendata);
1046 jd->rd = DNEW(registerdata);
1049 /* Allocate codeinfo memory from the heap as we need to keep them. */
1051 jd->code = code_codeinfo_new(m); /* XXX check allocation */
1053 /* get required compiler data */
1057 /* set the flags for the current JIT run */
1059 #if defined(ENABLE_PROFILING)
1061 jd->flags |= JITDATA_FLAG_INSTRUMENT;
1064 if (opt_verbosecall)
1065 jd->flags |= JITDATA_FLAG_VERBOSECALL;
1067 /* setup code generation stuff */
1069 #if defined(ENABLE_JIT)
1070 # if defined(ENABLE_INTRP)
1078 /* create new method descriptor with additional native parameters */
1081 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
1083 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
1084 md->paramcount * sizeof(typedesc) +
1085 nativeparams * sizeof(typedesc));
1087 nmd->paramcount = md->paramcount + nativeparams;
1089 nmd->params = DMNEW(paramdesc, nmd->paramcount);
1091 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
1093 if (m->flags & ACC_STATIC)
1094 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
1096 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
1099 #if defined(ENABLE_JIT)
1100 # if defined(ENABLE_INTRP)
1103 /* pre-allocate the arguments for the native ABI */
1105 md_param_alloc_native(nmd);
1108 /* generate the code */
1110 #if defined(ENABLE_JIT)
1111 # if defined(ENABLE_INTRP)
1113 intrp_createnativestub(f, jd, nmd);
1116 codegen_emit_stub_native(jd, nmd, f);
1118 intrp_createnativestub(f, jd, nmd);
1121 #if defined(ENABLE_STATISTICS)
1123 count_nstub_len += code->mcodelength;
1126 /* reallocate the memory and finish the code generation */
1130 #if !defined(NDEBUG)
1131 /* disassemble native stub */
1133 if (opt_shownativestub) {
1134 #if defined(ENABLE_DISASSEMBLER)
1135 codegen_disassemble_nativestub(m,
1136 (u1 *) (ptrint) code->entrypoint,
1137 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
1140 /* show data segment */
1142 if (opt_showddatasegment)
1145 #endif /* !defined(NDEBUG) */
1147 /* release memory */
1149 dump_release(dumpsize);
1151 /* return native stub code */
1157 /* codegen_disassemble_nativestub **********************************************
1159 Disassembles the generated native stub.
1161 *******************************************************************************/
1163 #if defined(ENABLE_DISASSEMBLER)
1164 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
1166 printf("Native stub: ");
1167 utf_fprint_printable_ascii_classname(stdout, m->class->name);
1169 utf_fprint_printable_ascii(stdout, m->name);
1170 utf_fprint_printable_ascii(stdout, m->descriptor);
1171 printf("\n\nLength: %d\n\n", (s4) (end - start));
1173 DISASSEMBLE(start, end);
1178 /* codegen_start_native_call ***************************************************
1180 Prepares the stuff required for a native (JNI) function call:
1182 - adds a stackframe info structure to the chain, for stacktraces
1183 - prepares the local references table on the stack
1185 The layout of the native stub stackframe should look like this:
1187 +---------------------------+ <- SP (of parent Java function)
1189 +---------------------------+
1191 | stackframe info structure |
1193 +---------------------------+
1195 | local references table |
1197 +---------------------------+
1199 | arguments (if any) |
1201 +---------------------------+ <- SP (native stub)
1203 *******************************************************************************/
1205 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
1207 stackframeinfo *sfi;
1208 localref_table *lrt;
1210 /* get data structures from stack */
1212 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1213 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1214 sizeof(localref_table));
1216 /* add a stackframeinfo to the chain */
1218 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1220 #if defined(ENABLE_JAVASE)
1221 /* add current JNI local references table to this thread */
1223 lrt->capacity = LOCALREFTABLE_CAPACITY;
1225 lrt->localframes = 1;
1226 lrt->prev = LOCALREFTABLE;
1228 /* clear the references array (memset is faster the a for-loop) */
1230 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1232 LOCALREFTABLE = lrt;
1237 /* codegen_finish_native_call **************************************************
1239 Removes the stuff required for a native (JNI) function call.
1240 Additionally it checks for an exceptions and in case, get the
1241 exception object and clear the pointer.
1243 *******************************************************************************/
1245 java_objectheader *codegen_finish_native_call(u1 *datasp)
1247 stackframeinfo *sfi;
1248 stackframeinfo **psfi;
1249 #if defined(ENABLE_JAVASE)
1250 localref_table *lrt;
1251 localref_table *plrt;
1254 java_objectheader *e;
1256 /* get data structures from stack */
1258 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1260 /* remove current stackframeinfo from chain */
1262 psfi = &STACKFRAMEINFO;
1266 #if defined(ENABLE_JAVASE)
1267 /* release JNI local references tables for this thread */
1269 lrt = LOCALREFTABLE;
1271 /* release all current local frames */
1273 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1274 /* get previous frame */
1278 /* Clear all reference entries (only for tables allocated on
1281 if (localframes > 1)
1282 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1286 /* set new local references table */
1291 /* now store the previous local frames in the thread structure */
1293 LOCALREFTABLE = lrt;
1296 /* get the exception and return it */
1298 e = exceptions_get_and_clear_exception();
1304 /* removecompilerstub **********************************************************
1306 Deletes a compilerstub from memory (simply by freeing it).
1308 *******************************************************************************/
1310 void removecompilerstub(u1 *stub)
1312 /* pass size 1 to keep the intern function happy */
1314 CFREE((void *) stub, 1);
1318 /* removenativestub ************************************************************
1320 Removes a previously created native-stub from memory.
1322 *******************************************************************************/
1324 void removenativestub(u1 *stub)
1326 /* pass size 1 to keep the intern function happy */
1328 CFREE((void *) stub, 1);
1332 /* codegen_reg_of_var **********************************************************
1334 This function determines a register, to which the result of an
1335 operation should go, when it is ultimatively intended to store the
1336 result in pseudoregister v. If v is assigned to an actual
1337 register, this register will be returned. Otherwise (when v is
1338 spilled) this function returns tempregnum. If not already done,
1339 regoff and flags are set in the stack location.
1341 On ARM we have to check if a long/double variable is splitted
1342 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1343 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1344 cases. (michi 2005/07/24)
1346 *******************************************************************************/
1348 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
1352 /* Do we have to generate a conditional move? Yes, then always
1353 return the temporary register. The real register is identified
1354 during the store. */
1356 if (opcode & ICMD_CONDITION_MASK)
1360 if (!(v->flags & INMEMORY)) {
1361 #if defined(__ARM__) && defined(__ARMEL__)
1362 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
1363 return PACK_REGS(GET_LOW_REG(v->vv.regoff),
1364 GET_HIGH_REG(tempregnum));
1366 #if defined(__ARM__) && defined(__ARMEB__)
1367 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
1368 return PACK_REGS(GET_LOW_REG(tempregnum),
1369 GET_HIGH_REG(v->vv.regoff));
1371 return v->vv.regoff;
1374 #if defined(ENABLE_STATISTICS)
1376 count_spills_read++;
1382 /* codegen_reg_of_dst **********************************************************
1384 This function determines a register, to which the result of an
1385 operation should go, when it is ultimatively intended to store the
1386 result in iptr->dst.var. If dst.var is assigned to an actual
1387 register, this register will be returned. Otherwise (when it is
1388 spilled) this function returns tempregnum. If not already done,
1389 regoff and flags are set in the stack location.
1391 On ARM we have to check if a long/double variable is splitted
1392 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1393 register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
1394 cases. (michi 2005/07/24)
1396 *******************************************************************************/
1398 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1400 return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
1404 #if defined(ENABLE_THREADS)
1405 void codegen_threadcritrestart(codegendata *cd, int offset)
1407 cd->threadcritcurrent.mcoderestart = offset;
1411 void codegen_threadcritstart(codegendata *cd, int offset)
1413 cd->threadcritcurrent.mcodebegin = offset;
1417 void codegen_threadcritstop(codegendata *cd, int offset)
1419 cd->threadcritcurrent.next = cd->threadcrit;
1420 cd->threadcritcurrent.mcodeend = offset;
1421 cd->threadcrit = DNEW(codegen_critical_section_t);
1422 *(cd->threadcrit) = cd->threadcritcurrent;
1423 cd->threadcritcount++;
1429 * These are local overrides for various environment variables in Emacs.
1430 * Please do not remove this and leave it at the end of the file, where
1431 * Emacs will automagically detect them.
1432 * ---------------------------------------------------------------------
1435 * indent-tabs-mode: t
1439 * vim:noexpandtab:sw=4:ts=4: