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 7785 2007-04-21 10:55:30Z edwin $
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"
102 #if defined(ENABLE_VMLOG)
103 #include <vmlog_cacao.h>
107 /* in this tree we store all method addresses *********************************/
109 static avl_tree *methodtree = NULL;
110 static s4 methodtree_comparator(const void *pc, const void *element);
113 /* codegen_init ****************************************************************
117 *******************************************************************************/
119 void codegen_init(void)
121 /* this tree is global, not method specific */
124 #if defined(ENABLE_JIT)
125 methodtree_element *mte;
128 methodtree = avl_create(&methodtree_comparator);
130 #if defined(ENABLE_JIT)
131 /* insert asm_vm_call_method */
133 mte = NEW(methodtree_element);
135 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
136 mte->endpc = (u1 *) (ptrint) asm_vm_call_method_end;
138 avl_insert(methodtree, mte);
139 #endif /* defined(ENABLE_JIT) */
144 /* codegen_setup ***************************************************************
146 Allocates and initialises code area, data area and references.
148 *******************************************************************************/
150 void codegen_setup(jitdata *jd)
155 /* get required compiler data */
160 /* initialize members */
164 cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
165 cd->mcodeend = cd->mcodebase + MCODEINITSIZE;
166 cd->mcodesize = MCODEINITSIZE;
168 /* initialize mcode variables */
170 cd->mcodeptr = cd->mcodebase;
171 cd->lastmcodeptr = cd->mcodebase;
173 #if defined(ENABLE_INTRP)
174 /* native dynamic superinstructions variables */
177 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
178 cd->ncodesize = NCODEINITSIZE;
180 /* initialize ncode variables */
182 cd->ncodeptr = cd->ncodebase;
184 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
185 cd->superstarts = NULL;
192 cd->jumpreferences = NULL;
194 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
195 cd->datareferences = NULL;
198 /* cd->patchrefs = list_create_dump(OFFSET(patchref, linkage)); */
199 cd->patchrefs = NULL;
200 cd->brancheslabel = list_create_dump(OFFSET(branch_label_ref_t, linkage));
202 cd->linenumberreferences = NULL;
203 cd->linenumbertablesizepos = 0;
204 cd->linenumbertablestartpos = 0;
205 cd->linenumbertab = 0;
207 #if defined(ENABLE_THREADS)
208 cd->threadcritcurrent.next = NULL;
209 cd->threadcritcount = 0;
214 /* codegen_reset ***************************************************************
216 Resets the codegen data structure so we can recompile the method.
218 *******************************************************************************/
220 static void codegen_reset(jitdata *jd)
226 /* get required compiler data */
231 /* reset error flag */
233 cd->flags &= ~CODEGENDATA_FLAG_ERROR;
235 /* reset some members, we reuse the code memory already allocated
236 as this should have almost the correct size */
238 cd->mcodeptr = cd->mcodebase;
239 cd->lastmcodeptr = cd->mcodebase;
244 cd->jumpreferences = NULL;
246 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
247 cd->datareferences = NULL;
250 /* cd->patchrefs = list_create_dump(OFFSET(patchref, linkage)); */
251 cd->patchrefs = NULL;
252 cd->brancheslabel = list_create_dump(OFFSET(branch_label_ref_t, linkage));
254 cd->linenumberreferences = NULL;
255 cd->linenumbertablesizepos = 0;
256 cd->linenumbertablestartpos = 0;
257 cd->linenumbertab = 0;
259 #if defined(ENABLE_THREADS)
260 cd->threadcritcurrent.next = NULL;
261 cd->threadcritcount = 0;
264 /* We need to clear the mpc and the branch references from all
265 basic blocks as they will definitely change. */
267 for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
269 bptr->branchrefs = NULL;
272 #if defined(ENABLE_REPLACEMENT)
273 code->rplpoints = NULL;
274 code->rplpointcount = 0;
275 code->regalloc = NULL;
276 code->regalloccount = 0;
277 code->globalcount = 0;
282 /* codegen_generate ************************************************************
284 Generates the code for the currently compiled method.
286 *******************************************************************************/
288 bool codegen_generate(jitdata *jd)
292 /* get required compiler data */
296 /* call the machine-dependent code generation function */
298 if (!codegen_emit(jd))
301 /* check for an error */
303 if (CODEGENDATA_HAS_FLAG_ERROR(cd)) {
304 /* check for long-branches flag, if it is set we recompile the
309 log_message_method("Re-generating code: ", jd->m);
312 /* XXX maybe we should tag long-branches-methods for recompilation */
314 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
315 /* we have to reset the codegendata structure first */
319 /* and restart the compiler run */
321 if (!codegen_emit(jd))
325 vm_abort("codegen_generate: unknown error occurred during codegen_emit: flags=%x\n", cd->flags);
330 log_message_method("Re-generating code done: ", jd->m);
334 /* reallocate the memory and finish the code generation */
338 /* everything's ok */
344 /* codegen_close ***************************************************************
348 *******************************************************************************/
350 void codegen_close(void)
352 /* TODO: release avl tree on i386 and x86_64 */
356 /* codegen_increase ************************************************************
360 *******************************************************************************/
362 void codegen_increase(codegendata *cd)
366 /* save old mcodebase pointer */
368 oldmcodebase = cd->mcodebase;
370 /* reallocate to new, doubled memory */
372 cd->mcodebase = DMREALLOC(cd->mcodebase,
377 cd->mcodeend = cd->mcodebase + cd->mcodesize;
379 /* set new mcodeptr */
381 cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
383 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
384 /* adjust the pointer to the last patcher position */
386 if (cd->lastmcodeptr != NULL)
387 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
392 /* codegen_ncode_increase ******************************************************
396 *******************************************************************************/
398 #if defined(ENABLE_INTRP)
399 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
403 /* save old ncodebase pointer */
405 oldncodebase = cd->ncodebase;
407 /* reallocate to new, doubled memory */
409 cd->ncodebase = DMREALLOC(cd->ncodebase,
415 /* return the new ncodeptr */
417 return (cd->ncodebase + (ncodeptr - oldncodebase));
422 /* codegen_add_branch_ref ******************************************************
424 Prepends an branch to the list.
426 *******************************************************************************/
428 void codegen_add_branch_ref(codegendata *cd, basicblock *target, s4 condition, s4 reg, u4 options)
433 STATISTICS(count_branches_unresolved++);
435 /* calculate the mpc of the branch instruction */
437 branchmpc = cd->mcodeptr - cd->mcodebase;
439 br = DNEW(branchref);
441 br->branchmpc = branchmpc;
442 br->condition = condition;
444 br->options = options;
445 br->next = target->branchrefs;
447 target->branchrefs = br;
451 /* codegen_resolve_branchrefs **************************************************
453 Resolves and patches the branch references of a given basic block.
455 *******************************************************************************/
457 void codegen_resolve_branchrefs(codegendata *cd, basicblock *bptr)
462 /* Save the mcodeptr because in the branch emitting functions
463 we generate code somewhere inside already generated code,
464 but we're still in the actual code generation phase. */
466 mcodeptr = cd->mcodeptr;
468 /* just to make sure */
470 assert(bptr->mpc >= 0);
472 for (br = bptr->branchrefs; br != NULL; br = br->next) {
473 /* temporary set the mcodeptr */
475 cd->mcodeptr = cd->mcodebase + br->branchmpc;
477 /* emit_bccz and emit_branch emit the correct code, even if we
478 pass condition == BRANCH_UNCONDITIONAL or reg == -1. */
480 emit_bccz(cd, bptr, br->condition, br->reg, br->options);
483 /* restore mcodeptr */
485 cd->mcodeptr = mcodeptr;
489 /* codegen_branch_label_add ****************************************************
491 Append an branch to the label-branch list.
493 *******************************************************************************/
495 void codegen_branch_label_add(codegendata *cd, s4 label, s4 condition, s4 reg, u4 options)
498 branch_label_ref_t *br;
501 /* get the label list */
503 list = cd->brancheslabel;
505 /* calculate the current mpc */
507 mpc = cd->mcodeptr - cd->mcodebase;
509 br = DNEW(branch_label_ref_t);
513 br->condition = condition;
515 br->options = options;
517 /* add the branch to the list */
519 list_add_last_unsynced(list, br);
523 /* codegen_add_patch_ref *******************************************************
525 Appends a new patcher reference to the list of patching positions.
527 *******************************************************************************/
529 void codegen_add_patch_ref(codegendata *cd, functionptr patcher, voidptr ref,
535 branchmpc = cd->mcodeptr - cd->mcodebase;
539 pr->branchpos = branchmpc;
541 pr->patcher = patcher;
544 /* list_add_first(cd->patchrefs, pr); */
545 pr->next = cd->patchrefs;
548 /* Generate NOPs for opt_shownops. */
553 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
554 /* On some architectures the patcher stub call instruction might
555 be longer than the actual instruction generated. On this
556 architectures we store the last patcher call position and after
557 the basic block code generation is completed, we check the
558 range and maybe generate some nop's. */
560 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
565 /* methodtree_comparator *******************************************************
567 Comparator function used for the AVL tree of methods.
569 *******************************************************************************/
571 static s4 methodtree_comparator(const void *pc, const void *element)
573 methodtree_element *mte;
574 methodtree_element *mtepc;
576 mte = (methodtree_element *) element;
577 mtepc = (methodtree_element *) pc;
579 /* compare both startpc and endpc of pc, even if they have the same value,
580 otherwise the avl_probe sometimes thinks the element is already in the
584 /* On S390 addresses are 31 bit. Compare only 31 bits of value.
586 # define ADDR_MASK(a) ((a) & 0x7FFFFFFF)
588 # define ADDR_MASK(a) (a)
591 if (ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->startpc) &&
592 ADDR_MASK((long) mtepc->startpc) <= ADDR_MASK((long) mte->endpc) &&
593 ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->endpc) &&
594 ADDR_MASK((long) mtepc->endpc) <= ADDR_MASK((long) mte->endpc)) {
597 } else if (ADDR_MASK((long) mtepc->startpc) < ADDR_MASK((long) mte->startpc)) {
608 /* codegen_insertmethod ********************************************************
610 Insert the machine code range of a method into the AVL tree of methods.
612 *******************************************************************************/
614 void codegen_insertmethod(u1 *startpc, u1 *endpc)
616 methodtree_element *mte;
618 /* allocate new method entry */
620 mte = NEW(methodtree_element);
622 mte->startpc = startpc;
625 /* this function does not return an error, but asserts for
628 avl_insert(methodtree, mte);
632 /* codegen_get_pv_from_pc ******************************************************
634 Find the PV for the given PC by searching in the AVL tree of
637 *******************************************************************************/
639 u1 *codegen_get_pv_from_pc(u1 *pc)
641 methodtree_element mtepc;
642 methodtree_element *mte;
644 /* allocation of the search structure on the stack is much faster */
649 mte = avl_find(methodtree, &mtepc);
652 /* No method was found. Let's dump a stacktrace. */
654 #if defined(ENABLE_VMLOG)
655 vmlog_cacao_signl("SIGSEGV");
658 log_println("We received a SIGSEGV and tried to handle it, but we were");
659 log_println("unable to find a Java method at:");
661 #if SIZEOF_VOID_P == 8
662 log_println("PC=0x%016lx", pc);
664 log_println("PC=0x%08x", pc);
667 log_println("Dumping the current stacktrace:");
669 #if defined(ENABLE_THREADS)
670 /* XXX michi: This should be available even without threads! */
671 threads_print_stacktrace();
674 vm_abort("Exiting...");
681 /* codegen_get_pv_from_pc_nocheck **********************************************
683 Find the PV for the given PC by searching in the AVL tree of
684 methods. This method does not check the return value and is used
687 *******************************************************************************/
689 u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
691 methodtree_element mtepc;
692 methodtree_element *mte;
694 /* allocation of the search structure on the stack is much faster */
699 mte = avl_find(methodtree, &mtepc);
708 /* codegen_set_replacement_point_notrap ****************************************
710 Record the position of a non-trappable replacement point.
712 *******************************************************************************/
714 #if defined(ENABLE_REPLACEMENT)
716 void codegen_set_replacement_point_notrap(codegendata *cd, s4 type)
718 void codegen_set_replacement_point_notrap(codegendata *cd)
721 assert(cd->replacementpoint);
722 assert(cd->replacementpoint->type == type);
723 assert(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP);
725 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
727 cd->replacementpoint++;
729 #endif /* defined(ENABLE_REPLACEMENT) */
732 /* codegen_set_replacement_point ***********************************************
734 Record the position of a trappable replacement point.
736 *******************************************************************************/
738 #if defined(ENABLE_REPLACEMENT)
740 void codegen_set_replacement_point(codegendata *cd, s4 type)
742 void codegen_set_replacement_point(codegendata *cd)
745 assert(cd->replacementpoint);
746 assert(cd->replacementpoint->type == type);
747 assert(!(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP));
749 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
751 cd->replacementpoint++;
753 /* XXX assert(cd->lastmcodeptr <= cd->mcodeptr); */
755 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
757 #endif /* defined(ENABLE_REPLACEMENT) */
760 /* codegen_finish **************************************************************
762 Finishes the code generation. A new memory, large enough for both
763 data and code, is allocated and data and code are copied together
764 to their final layout, unresolved jumps are resolved, ...
766 *******************************************************************************/
768 void codegen_finish(jitdata *jd)
773 #if defined(ENABLE_INTRP)
782 /* get required compiler data */
787 /* prevent compiler warning */
789 #if defined(ENABLE_INTRP)
793 /* calculate the code length */
795 mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
797 #if defined(ENABLE_THREADS)
798 extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
803 #if defined(ENABLE_STATISTICS)
805 count_code_len += mcodelen;
806 count_data_len += cd->dseglen;
810 alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
812 #if defined(ENABLE_INTRP)
814 ncodelen = cd->ncodeptr - cd->ncodebase;
816 ncodelen = 0; /* avoid compiler warning */
820 cd->dseglen = MEMORY_ALIGN(cd->dseglen, MAX_ALIGN);
821 alignedlen = alignedmcodelen + cd->dseglen;
823 #if defined(ENABLE_INTRP)
825 alignedlen += ncodelen;
829 /* allocate new memory */
831 code->mcodelength = mcodelen + cd->dseglen;
832 code->mcode = CNEW(u1, alignedlen + extralen);
834 /* set the entrypoint of the method */
836 assert(code->entrypoint == NULL);
837 code->entrypoint = epoint = (code->mcode + cd->dseglen);
839 /* fill the data segment (code->entrypoint must already be set!) */
843 /* copy code to the new location */
845 MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
847 #if defined(ENABLE_INTRP)
848 /* relocate native dynamic superinstruction code (if any) */
851 cd->mcodebase = code->entrypoint;
854 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
856 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
858 /* flush the instruction and data caches */
860 md_cacheflush(ncodebase, ncodelen);
862 /* set some cd variables for dynamic_super_rerwite */
864 cd->ncodebase = ncodebase;
867 cd->ncodebase = NULL;
870 dynamic_super_rewrite(cd);
874 /* jump table resolving */
876 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
877 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
878 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
880 /* line number table resolving */
886 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
888 target = lr->targetmpc;
889 /* if the entry contains an mcode pointer (normal case), resolve it */
890 /* (see doc/inlining_stacktrace.txt for details) */
891 if (lr->linenumber >= -2) {
892 target += (ptrint) epoint;
894 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
895 (functionptr) target;
898 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
899 (functionptr) ((ptrint) epoint + cd->linenumbertab);
901 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
904 #if defined(ENABLE_REPLACEMENT)
905 /* replacement point resolving */
910 code->replacementstubs += (ptrint) epoint;
912 rp = code->rplpoints;
913 for (i=0; i<code->rplpointcount; ++i, ++rp) {
914 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
917 #endif /* defined(ENABLE_REPLACEMENT) */
919 /* add method into methodtree to find the entrypoint */
921 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
923 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
924 /* resolve data segment references */
926 dseg_resolve_datareferences(jd);
929 #if defined(ENABLE_THREADS)
931 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
933 codegen_critical_section_t *nt = cd->threadcrit;
935 for (i = 0; i < cd->threadcritcount; i++) {
936 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
937 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
938 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
939 critical_register_critical_section(n);
946 /* flush the instruction and data caches */
948 md_cacheflush(code->mcode, code->mcodelength);
952 /* codegen_generate_stub_compiler **********************************************
954 Wrapper for codegen_emit_stub_compiler.
957 pointer to the compiler stub code.
959 *******************************************************************************/
961 u1 *codegen_generate_stub_compiler(methodinfo *m)
965 ptrint *d; /* pointer to data memory */
966 u1 *c; /* pointer to code memory */
969 /* mark dump memory */
971 dumpsize = dump_size();
973 /* allocate required data structures */
978 jd->cd = DNEW(codegendata);
981 /* get required compiler data */
985 /* allocate code memory */
987 c = CNEW(u1, 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE);
989 /* set pointers correctly */
995 c = c + 3 * SIZEOF_VOID_P;
998 /* NOTE: The codeinfo pointer is actually a pointer to the
999 methodinfo (this fakes a codeinfo structure). */
1001 d[0] = (ptrint) asm_call_jit_compiler;
1003 d[2] = (ptrint) &d[1]; /* fake code->m */
1005 /* call the emit function */
1007 codegen_emit_stub_compiler(jd);
1009 #if defined(ENABLE_STATISTICS)
1011 count_cstub_len += 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE;
1016 md_cacheflush(cd->mcodebase, 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE);
1018 /* release dump memory */
1020 dump_release(dumpsize);
1022 /* return native stub code */
1028 /* codegen_generate_stub_native ************************************************
1030 Wrapper for codegen_emit_stub_native.
1033 the codeinfo representing the stub code.
1035 *******************************************************************************/
1037 codeinfo *codegen_generate_stub_native(methodinfo *m, functionptr f)
1046 /* mark dump memory */
1048 dumpsize = dump_size();
1053 jd->cd = DNEW(codegendata);
1054 jd->rd = DNEW(registerdata);
1057 /* Allocate codeinfo memory from the heap as we need to keep them. */
1059 jd->code = code_codeinfo_new(m); /* XXX check allocation */
1061 /* get required compiler data */
1065 /* set the flags for the current JIT run */
1067 #if defined(ENABLE_PROFILING)
1069 jd->flags |= JITDATA_FLAG_INSTRUMENT;
1072 if (opt_verbosecall)
1073 jd->flags |= JITDATA_FLAG_VERBOSECALL;
1075 /* setup code generation stuff */
1077 #if defined(ENABLE_JIT)
1078 # if defined(ENABLE_INTRP)
1086 /* create new method descriptor with additional native parameters */
1089 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
1091 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
1092 md->paramcount * sizeof(typedesc) +
1093 nativeparams * sizeof(typedesc));
1095 nmd->paramcount = md->paramcount + nativeparams;
1097 nmd->params = DMNEW(paramdesc, nmd->paramcount);
1099 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
1101 if (m->flags & ACC_STATIC)
1102 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
1104 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
1107 #if defined(ENABLE_JIT)
1108 # if defined(ENABLE_INTRP)
1111 /* pre-allocate the arguments for the native ABI */
1113 md_param_alloc_native(nmd);
1116 /* generate the code */
1118 #if defined(ENABLE_JIT)
1119 # if defined(ENABLE_INTRP)
1121 intrp_createnativestub(f, jd, nmd);
1124 codegen_emit_stub_native(jd, nmd, f);
1126 intrp_createnativestub(f, jd, nmd);
1129 #if defined(ENABLE_STATISTICS)
1131 count_nstub_len += code->mcodelength;
1134 /* reallocate the memory and finish the code generation */
1138 #if !defined(NDEBUG)
1139 /* disassemble native stub */
1141 if (opt_shownativestub) {
1142 #if defined(ENABLE_DISASSEMBLER)
1143 codegen_disassemble_nativestub(m,
1144 (u1 *) (ptrint) code->entrypoint,
1145 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
1148 /* show data segment */
1150 if (opt_showddatasegment)
1153 #endif /* !defined(NDEBUG) */
1155 /* release memory */
1157 dump_release(dumpsize);
1159 /* return native stub code */
1165 /* codegen_disassemble_nativestub **********************************************
1167 Disassembles the generated native stub.
1169 *******************************************************************************/
1171 #if defined(ENABLE_DISASSEMBLER)
1172 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
1174 printf("Native stub: ");
1175 utf_fprint_printable_ascii_classname(stdout, m->class->name);
1177 utf_fprint_printable_ascii(stdout, m->name);
1178 utf_fprint_printable_ascii(stdout, m->descriptor);
1179 printf("\n\nLength: %d\n\n", (s4) (end - start));
1181 DISASSEMBLE(start, end);
1186 /* codegen_start_native_call ***************************************************
1188 Prepares the stuff required for a native (JNI) function call:
1190 - adds a stackframe info structure to the chain, for stacktraces
1191 - prepares the local references table on the stack
1193 The layout of the native stub stackframe should look like this:
1195 +---------------------------+ <- SP (of parent Java function)
1197 +---------------------------+
1199 | stackframe info structure |
1201 +---------------------------+
1203 | local references table |
1205 +---------------------------+
1207 | arguments (if any) |
1209 +---------------------------+ <- SP (native stub)
1211 *******************************************************************************/
1213 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
1215 stackframeinfo *sfi;
1216 localref_table *lrt;
1218 /* get data structures from stack */
1220 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1221 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1222 sizeof(localref_table));
1224 /* add a stackframeinfo to the chain */
1226 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1228 #if defined(ENABLE_JAVASE)
1229 /* add current JNI local references table to this thread */
1231 lrt->capacity = LOCALREFTABLE_CAPACITY;
1233 lrt->localframes = 1;
1234 lrt->prev = LOCALREFTABLE;
1236 /* clear the references array (memset is faster the a for-loop) */
1238 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1240 LOCALREFTABLE = lrt;
1245 /* codegen_finish_native_call **************************************************
1247 Removes the stuff required for a native (JNI) function call.
1248 Additionally it checks for an exceptions and in case, get the
1249 exception object and clear the pointer.
1251 *******************************************************************************/
1253 java_objectheader *codegen_finish_native_call(u1 *datasp)
1255 stackframeinfo *sfi;
1256 stackframeinfo **psfi;
1257 #if defined(ENABLE_JAVASE)
1258 localref_table *lrt;
1259 localref_table *plrt;
1262 java_objectheader *e;
1264 /* get data structures from stack */
1266 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1268 /* remove current stackframeinfo from chain */
1270 psfi = &STACKFRAMEINFO;
1274 #if defined(ENABLE_JAVASE)
1275 /* release JNI local references tables for this thread */
1277 lrt = LOCALREFTABLE;
1279 /* release all current local frames */
1281 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1282 /* get previous frame */
1286 /* Clear all reference entries (only for tables allocated on
1289 if (localframes > 1)
1290 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1294 /* set new local references table */
1299 /* now store the previous local frames in the thread structure */
1301 LOCALREFTABLE = lrt;
1304 /* get the exception and return it */
1306 e = exceptions_get_and_clear_exception();
1312 /* removecompilerstub **********************************************************
1314 Deletes a compilerstub from memory (simply by freeing it).
1316 *******************************************************************************/
1318 void removecompilerstub(u1 *stub)
1320 /* pass size 1 to keep the intern function happy */
1322 CFREE((void *) stub, 1);
1326 /* removenativestub ************************************************************
1328 Removes a previously created native-stub from memory.
1330 *******************************************************************************/
1332 void removenativestub(u1 *stub)
1334 /* pass size 1 to keep the intern function happy */
1336 CFREE((void *) stub, 1);
1340 /* codegen_reg_of_var **********************************************************
1342 This function determines a register, to which the result of an
1343 operation should go, when it is ultimatively intended to store the
1344 result in pseudoregister v. If v is assigned to an actual
1345 register, this register will be returned. Otherwise (when v is
1346 spilled) this function returns tempregnum. If not already done,
1347 regoff and flags are set in the stack location.
1349 On ARM we have to check if a long/double variable is splitted
1350 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1351 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1352 cases. (michi 2005/07/24)
1354 *******************************************************************************/
1356 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
1360 /* Do we have to generate a conditional move? Yes, then always
1361 return the temporary register. The real register is identified
1362 during the store. */
1364 if (opcode & ICMD_CONDITION_MASK)
1368 if (!(v->flags & INMEMORY)) {
1369 #if defined(__ARM__) && defined(__ARMEL__)
1370 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
1371 return PACK_REGS(GET_LOW_REG(v->vv.regoff),
1372 GET_HIGH_REG(tempregnum));
1374 #if defined(__ARM__) && defined(__ARMEB__)
1375 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
1376 return PACK_REGS(GET_LOW_REG(tempregnum),
1377 GET_HIGH_REG(v->vv.regoff));
1379 return v->vv.regoff;
1382 #if defined(ENABLE_STATISTICS)
1384 count_spills_read++;
1390 /* codegen_reg_of_dst **********************************************************
1392 This function determines a register, to which the result of an
1393 operation should go, when it is ultimatively intended to store the
1394 result in iptr->dst.var. If dst.var is assigned to an actual
1395 register, this register will be returned. Otherwise (when it is
1396 spilled) this function returns tempregnum. If not already done,
1397 regoff and flags are set in the stack location.
1399 On ARM we have to check if a long/double variable is splitted
1400 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1401 register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
1402 cases. (michi 2005/07/24)
1404 *******************************************************************************/
1406 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1408 return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
1412 #if defined(ENABLE_THREADS)
1413 void codegen_threadcritrestart(codegendata *cd, int offset)
1415 cd->threadcritcurrent.mcoderestart = offset;
1419 void codegen_threadcritstart(codegendata *cd, int offset)
1421 cd->threadcritcurrent.mcodebegin = offset;
1425 void codegen_threadcritstop(codegendata *cd, int offset)
1427 cd->threadcritcurrent.next = cd->threadcrit;
1428 cd->threadcritcurrent.mcodeend = offset;
1429 cd->threadcrit = DNEW(codegen_critical_section_t);
1430 *(cd->threadcrit) = cd->threadcritcurrent;
1431 cd->threadcritcount++;
1437 * These are local overrides for various environment variables in Emacs.
1438 * Please do not remove this and leave it at the end of the file, where
1439 * Emacs will automagically detect them.
1440 * ---------------------------------------------------------------------
1443 * indent-tabs-mode: t
1447 * vim:noexpandtab:sw=4:ts=4: