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 7797 2007-04-23 20:12:39Z 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/builtin.h"
76 #include "vm/exceptions.h"
77 #include "vm/stringlocal.h"
79 #include "vm/jit/abi.h"
80 #include "vm/jit/asmpart.h"
81 #include "vm/jit/codegen-common.h"
83 #if defined(ENABLE_DISASSEMBLER)
84 # include "vm/jit/disass.h"
87 #include "vm/jit/dseg.h"
88 #include "vm/jit/emit-common.h"
89 #include "vm/jit/jit.h"
90 #include "vm/jit/md.h"
91 #include "vm/jit/replace.h"
92 #include "vm/jit/stacktrace.h"
94 #if defined(ENABLE_INTRP)
95 #include "vm/jit/intrp/intrp.h"
98 #include "vmcore/method.h"
99 #include "vmcore/options.h"
101 # include "vmcore/statistics.h"
103 #if defined(ENABLE_VMLOG)
104 #include <vmlog_cacao.h>
108 /* in this tree we store all method addresses *********************************/
110 static avl_tree *methodtree = NULL;
111 static s4 methodtree_comparator(const void *pc, const void *element);
114 /* codegen_init ****************************************************************
118 *******************************************************************************/
120 void codegen_init(void)
122 /* this tree is global, not method specific */
125 #if defined(ENABLE_JIT)
126 methodtree_element *mte;
129 methodtree = avl_create(&methodtree_comparator);
131 #if defined(ENABLE_JIT)
132 /* insert asm_vm_call_method */
134 mte = NEW(methodtree_element);
136 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
137 mte->endpc = (u1 *) (ptrint) asm_vm_call_method_end;
139 avl_insert(methodtree, mte);
140 #endif /* defined(ENABLE_JIT) */
145 /* codegen_setup ***************************************************************
147 Allocates and initialises code area, data area and references.
149 *******************************************************************************/
151 void codegen_setup(jitdata *jd)
156 /* get required compiler data */
161 /* initialize members */
165 cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
166 cd->mcodeend = cd->mcodebase + MCODEINITSIZE;
167 cd->mcodesize = MCODEINITSIZE;
169 /* initialize mcode variables */
171 cd->mcodeptr = cd->mcodebase;
172 cd->lastmcodeptr = cd->mcodebase;
174 #if defined(ENABLE_INTRP)
175 /* native dynamic superinstructions variables */
178 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
179 cd->ncodesize = NCODEINITSIZE;
181 /* initialize ncode variables */
183 cd->ncodeptr = cd->ncodebase;
185 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
186 cd->superstarts = NULL;
193 cd->jumpreferences = NULL;
195 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
196 cd->datareferences = NULL;
199 /* cd->patchrefs = list_create_dump(OFFSET(patchref, linkage)); */
200 cd->patchrefs = NULL;
201 cd->brancheslabel = list_create_dump(OFFSET(branch_label_ref_t, linkage));
203 cd->linenumberreferences = NULL;
204 cd->linenumbertablesizepos = 0;
205 cd->linenumbertablestartpos = 0;
206 cd->linenumbertab = 0;
208 #if defined(ENABLE_THREADS)
209 cd->threadcritcurrent.next = NULL;
210 cd->threadcritcount = 0;
215 /* codegen_reset ***************************************************************
217 Resets the codegen data structure so we can recompile the method.
219 *******************************************************************************/
221 static void codegen_reset(jitdata *jd)
227 /* get required compiler data */
232 /* reset error flag */
234 cd->flags &= ~CODEGENDATA_FLAG_ERROR;
236 /* reset some members, we reuse the code memory already allocated
237 as this should have almost the correct size */
239 cd->mcodeptr = cd->mcodebase;
240 cd->lastmcodeptr = cd->mcodebase;
245 cd->jumpreferences = NULL;
247 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
248 cd->datareferences = NULL;
251 /* cd->patchrefs = list_create_dump(OFFSET(patchref, linkage)); */
252 cd->patchrefs = NULL;
253 cd->brancheslabel = list_create_dump(OFFSET(branch_label_ref_t, linkage));
255 cd->linenumberreferences = NULL;
256 cd->linenumbertablesizepos = 0;
257 cd->linenumbertablestartpos = 0;
258 cd->linenumbertab = 0;
260 #if defined(ENABLE_THREADS)
261 cd->threadcritcurrent.next = NULL;
262 cd->threadcritcount = 0;
265 /* We need to clear the mpc and the branch references from all
266 basic blocks as they will definitely change. */
268 for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
270 bptr->branchrefs = NULL;
273 #if defined(ENABLE_REPLACEMENT)
274 code->rplpoints = NULL;
275 code->rplpointcount = 0;
276 code->regalloc = NULL;
277 code->regalloccount = 0;
278 code->globalcount = 0;
283 /* codegen_generate ************************************************************
285 Generates the code for the currently compiled method.
287 *******************************************************************************/
289 bool codegen_generate(jitdata *jd)
293 /* get required compiler data */
297 /* call the machine-dependent code generation function */
299 if (!codegen_emit(jd))
302 /* check for an error */
304 if (CODEGENDATA_HAS_FLAG_ERROR(cd)) {
305 /* check for long-branches flag, if it is set we recompile the
310 log_message_method("Re-generating code: ", jd->m);
313 /* XXX maybe we should tag long-branches-methods for recompilation */
315 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
316 /* we have to reset the codegendata structure first */
320 /* and restart the compiler run */
322 if (!codegen_emit(jd))
326 vm_abort("codegen_generate: unknown error occurred during codegen_emit: flags=%x\n", cd->flags);
331 log_message_method("Re-generating code done: ", jd->m);
335 /* reallocate the memory and finish the code generation */
339 /* everything's ok */
345 /* codegen_close ***************************************************************
349 *******************************************************************************/
351 void codegen_close(void)
353 /* TODO: release avl tree on i386 and x86_64 */
357 /* codegen_increase ************************************************************
361 *******************************************************************************/
363 void codegen_increase(codegendata *cd)
367 /* save old mcodebase pointer */
369 oldmcodebase = cd->mcodebase;
371 /* reallocate to new, doubled memory */
373 cd->mcodebase = DMREALLOC(cd->mcodebase,
378 cd->mcodeend = cd->mcodebase + cd->mcodesize;
380 /* set new mcodeptr */
382 cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
384 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
385 /* adjust the pointer to the last patcher position */
387 if (cd->lastmcodeptr != NULL)
388 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
393 /* codegen_ncode_increase ******************************************************
397 *******************************************************************************/
399 #if defined(ENABLE_INTRP)
400 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
404 /* save old ncodebase pointer */
406 oldncodebase = cd->ncodebase;
408 /* reallocate to new, doubled memory */
410 cd->ncodebase = DMREALLOC(cd->ncodebase,
416 /* return the new ncodeptr */
418 return (cd->ncodebase + (ncodeptr - oldncodebase));
423 /* codegen_add_branch_ref ******************************************************
425 Prepends an branch to the list.
427 *******************************************************************************/
429 void codegen_add_branch_ref(codegendata *cd, basicblock *target, s4 condition, s4 reg, u4 options)
434 STATISTICS(count_branches_unresolved++);
436 /* calculate the mpc of the branch instruction */
438 branchmpc = cd->mcodeptr - cd->mcodebase;
440 br = DNEW(branchref);
442 br->branchmpc = branchmpc;
443 br->condition = condition;
445 br->options = options;
446 br->next = target->branchrefs;
448 target->branchrefs = br;
452 /* codegen_resolve_branchrefs **************************************************
454 Resolves and patches the branch references of a given basic block.
456 *******************************************************************************/
458 void codegen_resolve_branchrefs(codegendata *cd, basicblock *bptr)
463 /* Save the mcodeptr because in the branch emitting functions
464 we generate code somewhere inside already generated code,
465 but we're still in the actual code generation phase. */
467 mcodeptr = cd->mcodeptr;
469 /* just to make sure */
471 assert(bptr->mpc >= 0);
473 for (br = bptr->branchrefs; br != NULL; br = br->next) {
474 /* temporary set the mcodeptr */
476 cd->mcodeptr = cd->mcodebase + br->branchmpc;
478 /* emit_bccz and emit_branch emit the correct code, even if we
479 pass condition == BRANCH_UNCONDITIONAL or reg == -1. */
481 emit_bccz(cd, bptr, br->condition, br->reg, br->options);
484 /* restore mcodeptr */
486 cd->mcodeptr = mcodeptr;
490 /* codegen_branch_label_add ****************************************************
492 Append an branch to the label-branch list.
494 *******************************************************************************/
496 void codegen_branch_label_add(codegendata *cd, s4 label, s4 condition, s4 reg, u4 options)
499 branch_label_ref_t *br;
502 /* get the label list */
504 list = cd->brancheslabel;
506 /* calculate the current mpc */
508 mpc = cd->mcodeptr - cd->mcodebase;
510 br = DNEW(branch_label_ref_t);
514 br->condition = condition;
516 br->options = options;
518 /* add the branch to the list */
520 list_add_last_unsynced(list, br);
524 /* codegen_add_patch_ref *******************************************************
526 Appends a new patcher reference to the list of patching positions.
528 *******************************************************************************/
530 void codegen_add_patch_ref(codegendata *cd, functionptr patcher, voidptr ref,
536 branchmpc = cd->mcodeptr - cd->mcodebase;
540 pr->branchpos = branchmpc;
542 pr->patcher = patcher;
545 /* list_add_first(cd->patchrefs, pr); */
546 pr->next = cd->patchrefs;
549 /* Generate NOPs for opt_shownops. */
554 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
555 /* On some architectures the patcher stub call instruction might
556 be longer than the actual instruction generated. On this
557 architectures we store the last patcher call position and after
558 the basic block code generation is completed, we check the
559 range and maybe generate some nop's. */
561 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
566 /* methodtree_comparator *******************************************************
568 Comparator function used for the AVL tree of methods.
570 *******************************************************************************/
572 static s4 methodtree_comparator(const void *pc, const void *element)
574 methodtree_element *mte;
575 methodtree_element *mtepc;
577 mte = (methodtree_element *) element;
578 mtepc = (methodtree_element *) pc;
580 /* compare both startpc and endpc of pc, even if they have the same value,
581 otherwise the avl_probe sometimes thinks the element is already in the
585 /* On S390 addresses are 31 bit. Compare only 31 bits of value.
587 # define ADDR_MASK(a) ((a) & 0x7FFFFFFF)
589 # define ADDR_MASK(a) (a)
592 if (ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->startpc) &&
593 ADDR_MASK((long) mtepc->startpc) <= ADDR_MASK((long) mte->endpc) &&
594 ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->endpc) &&
595 ADDR_MASK((long) mtepc->endpc) <= ADDR_MASK((long) mte->endpc)) {
598 } else if (ADDR_MASK((long) mtepc->startpc) < ADDR_MASK((long) mte->startpc)) {
609 /* codegen_insertmethod ********************************************************
611 Insert the machine code range of a method into the AVL tree of methods.
613 *******************************************************************************/
615 void codegen_insertmethod(u1 *startpc, u1 *endpc)
617 methodtree_element *mte;
619 /* allocate new method entry */
621 mte = NEW(methodtree_element);
623 mte->startpc = startpc;
626 /* this function does not return an error, but asserts for
629 avl_insert(methodtree, mte);
633 /* codegen_get_pv_from_pc ******************************************************
635 Find the PV for the given PC by searching in the AVL tree of
638 *******************************************************************************/
640 u1 *codegen_get_pv_from_pc(u1 *pc)
642 methodtree_element mtepc;
643 methodtree_element *mte;
645 /* allocation of the search structure on the stack is much faster */
650 mte = avl_find(methodtree, &mtepc);
653 /* No method was found. Let's dump a stacktrace. */
655 #if defined(ENABLE_VMLOG)
656 vmlog_cacao_signl("SIGSEGV");
659 log_println("We received a SIGSEGV and tried to handle it, but we were");
660 log_println("unable to find a Java method at:");
662 #if SIZEOF_VOID_P == 8
663 log_println("PC=0x%016lx", pc);
665 log_println("PC=0x%08x", pc);
668 log_println("Dumping the current stacktrace:");
670 #if defined(ENABLE_THREADS)
671 /* XXX michi: This should be available even without threads! */
672 threads_print_stacktrace();
675 vm_abort("Exiting...");
682 /* codegen_get_pv_from_pc_nocheck **********************************************
684 Find the PV for the given PC by searching in the AVL tree of
685 methods. This method does not check the return value and is used
688 *******************************************************************************/
690 u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
692 methodtree_element mtepc;
693 methodtree_element *mte;
695 /* allocation of the search structure on the stack is much faster */
700 mte = avl_find(methodtree, &mtepc);
709 /* codegen_set_replacement_point_notrap ****************************************
711 Record the position of a non-trappable replacement point.
713 *******************************************************************************/
715 #if defined(ENABLE_REPLACEMENT)
717 void codegen_set_replacement_point_notrap(codegendata *cd, s4 type)
719 void codegen_set_replacement_point_notrap(codegendata *cd)
722 assert(cd->replacementpoint);
723 assert(cd->replacementpoint->type == type);
724 assert(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP);
726 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
728 cd->replacementpoint++;
730 #endif /* defined(ENABLE_REPLACEMENT) */
733 /* codegen_set_replacement_point ***********************************************
735 Record the position of a trappable replacement point.
737 *******************************************************************************/
739 #if defined(ENABLE_REPLACEMENT)
741 void codegen_set_replacement_point(codegendata *cd, s4 type)
743 void codegen_set_replacement_point(codegendata *cd)
746 assert(cd->replacementpoint);
747 assert(cd->replacementpoint->type == type);
748 assert(!(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP));
750 cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
752 cd->replacementpoint++;
754 /* XXX assert(cd->lastmcodeptr <= cd->mcodeptr); */
756 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
758 #endif /* defined(ENABLE_REPLACEMENT) */
761 /* codegen_finish **************************************************************
763 Finishes the code generation. A new memory, large enough for both
764 data and code, is allocated and data and code are copied together
765 to their final layout, unresolved jumps are resolved, ...
767 *******************************************************************************/
769 void codegen_finish(jitdata *jd)
774 #if defined(ENABLE_INTRP)
783 /* get required compiler data */
788 /* prevent compiler warning */
790 #if defined(ENABLE_INTRP)
794 /* calculate the code length */
796 mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
798 #if defined(ENABLE_THREADS)
799 extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
804 #if defined(ENABLE_STATISTICS)
806 count_code_len += mcodelen;
807 count_data_len += cd->dseglen;
811 alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
813 #if defined(ENABLE_INTRP)
815 ncodelen = cd->ncodeptr - cd->ncodebase;
817 ncodelen = 0; /* avoid compiler warning */
821 cd->dseglen = MEMORY_ALIGN(cd->dseglen, MAX_ALIGN);
822 alignedlen = alignedmcodelen + cd->dseglen;
824 #if defined(ENABLE_INTRP)
826 alignedlen += ncodelen;
830 /* allocate new memory */
832 code->mcodelength = mcodelen + cd->dseglen;
833 code->mcode = CNEW(u1, alignedlen + extralen);
835 /* set the entrypoint of the method */
837 assert(code->entrypoint == NULL);
838 code->entrypoint = epoint = (code->mcode + cd->dseglen);
840 /* fill the data segment (code->entrypoint must already be set!) */
844 /* copy code to the new location */
846 MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
848 #if defined(ENABLE_INTRP)
849 /* relocate native dynamic superinstruction code (if any) */
852 cd->mcodebase = code->entrypoint;
855 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
857 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
859 /* flush the instruction and data caches */
861 md_cacheflush(ncodebase, ncodelen);
863 /* set some cd variables for dynamic_super_rerwite */
865 cd->ncodebase = ncodebase;
868 cd->ncodebase = NULL;
871 dynamic_super_rewrite(cd);
875 /* jump table resolving */
877 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
878 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
879 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
881 /* line number table resolving */
887 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
889 target = lr->targetmpc;
890 /* if the entry contains an mcode pointer (normal case), resolve it */
891 /* (see doc/inlining_stacktrace.txt for details) */
892 if (lr->linenumber >= -2) {
893 target += (ptrint) epoint;
895 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
896 (functionptr) target;
899 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
900 (functionptr) ((ptrint) epoint + cd->linenumbertab);
902 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
905 #if defined(ENABLE_REPLACEMENT)
906 /* replacement point resolving */
911 code->replacementstubs += (ptrint) epoint;
913 rp = code->rplpoints;
914 for (i=0; i<code->rplpointcount; ++i, ++rp) {
915 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
918 #endif /* defined(ENABLE_REPLACEMENT) */
920 /* add method into methodtree to find the entrypoint */
922 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
924 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
925 /* resolve data segment references */
927 dseg_resolve_datareferences(jd);
930 #if defined(ENABLE_THREADS)
932 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
934 codegen_critical_section_t *nt = cd->threadcrit;
936 for (i = 0; i < cd->threadcritcount; i++) {
937 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
938 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
939 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
940 critical_register_critical_section(n);
947 /* flush the instruction and data caches */
949 md_cacheflush(code->mcode, code->mcodelength);
953 /* codegen_generate_stub_compiler **********************************************
955 Wrapper for codegen_emit_stub_compiler.
958 pointer to the compiler stub code.
960 *******************************************************************************/
962 u1 *codegen_generate_stub_compiler(methodinfo *m)
966 ptrint *d; /* pointer to data memory */
967 u1 *c; /* pointer to code memory */
970 /* mark dump memory */
972 dumpsize = dump_size();
974 /* allocate required data structures */
979 jd->cd = DNEW(codegendata);
982 /* get required compiler data */
986 /* allocate code memory */
988 c = CNEW(u1, 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE);
990 /* set pointers correctly */
996 c = c + 3 * SIZEOF_VOID_P;
999 /* NOTE: The codeinfo pointer is actually a pointer to the
1000 methodinfo (this fakes a codeinfo structure). */
1002 d[0] = (ptrint) asm_call_jit_compiler;
1004 d[2] = (ptrint) &d[1]; /* fake code->m */
1006 /* call the emit function */
1008 codegen_emit_stub_compiler(jd);
1010 #if defined(ENABLE_STATISTICS)
1012 count_cstub_len += 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE;
1017 md_cacheflush(cd->mcodebase, 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE);
1019 /* release dump memory */
1021 dump_release(dumpsize);
1023 /* return native stub code */
1029 /* codegen_generate_stub_builtin ***********************************************
1031 Wrapper for codegen_emit_stub_builtin.
1034 Pointer to the entrypoint of the stub.
1036 *******************************************************************************/
1038 void codegen_generate_stub_builtin(builtintable_entry *bte)
1044 /* mark dump memory */
1046 dumpsize = dump_size();
1051 jd->cd = DNEW(codegendata);
1055 /* Allocate codeinfo memory from the heap as we need to keep them. */
1057 jd->code = code_codeinfo_new(NULL);
1059 /* get required compiler data */
1063 /* setup code generation stuff */
1067 /* generate the code */
1069 #if defined(ENABLE_JIT)
1070 # if defined(ENABLE_INTRP)
1073 codegen_emit_stub_builtin(jd, bte);
1076 /* reallocate the memory and finish the code generation */
1080 /* set the stub entry point in the builtin table */
1082 bte->stub = code->entrypoint;
1084 #if defined(ENABLE_STATISTICS)
1086 count_nstub_len += code->mcodelength;
1089 /* release memory */
1091 dump_release(dumpsize);
1095 /* codegen_generate_stub_native ************************************************
1097 Wrapper for codegen_emit_stub_native.
1100 the codeinfo representing the stub code.
1102 *******************************************************************************/
1104 codeinfo *codegen_generate_stub_native(methodinfo *m, functionptr f)
1113 /* mark dump memory */
1115 dumpsize = dump_size();
1120 jd->cd = DNEW(codegendata);
1121 jd->rd = DNEW(registerdata);
1124 /* Allocate codeinfo memory from the heap as we need to keep them. */
1126 jd->code = code_codeinfo_new(m); /* XXX check allocation */
1128 /* get required compiler data */
1132 /* set the flags for the current JIT run */
1134 #if defined(ENABLE_PROFILING)
1136 jd->flags |= JITDATA_FLAG_INSTRUMENT;
1139 if (opt_verbosecall)
1140 jd->flags |= JITDATA_FLAG_VERBOSECALL;
1142 /* setup code generation stuff */
1144 #if defined(ENABLE_JIT)
1145 # if defined(ENABLE_INTRP)
1153 /* create new method descriptor with additional native parameters */
1156 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
1158 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
1159 md->paramcount * sizeof(typedesc) +
1160 nativeparams * sizeof(typedesc));
1162 nmd->paramcount = md->paramcount + nativeparams;
1164 nmd->params = DMNEW(paramdesc, nmd->paramcount);
1166 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
1168 if (m->flags & ACC_STATIC)
1169 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
1171 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
1174 #if defined(ENABLE_JIT)
1175 # if defined(ENABLE_INTRP)
1178 /* pre-allocate the arguments for the native ABI */
1180 md_param_alloc_native(nmd);
1183 /* generate the code */
1185 #if defined(ENABLE_JIT)
1186 # if defined(ENABLE_INTRP)
1188 intrp_createnativestub(f, jd, nmd);
1191 codegen_emit_stub_native(jd, nmd, f);
1193 intrp_createnativestub(f, jd, nmd);
1196 /* reallocate the memory and finish the code generation */
1200 #if defined(ENABLE_STATISTICS)
1202 count_nstub_len += code->mcodelength;
1205 #if !defined(NDEBUG)
1206 /* disassemble native stub */
1208 if (opt_shownativestub) {
1209 #if defined(ENABLE_DISASSEMBLER)
1210 codegen_disassemble_nativestub(m,
1211 (u1 *) (ptrint) code->entrypoint,
1212 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
1215 /* show data segment */
1217 if (opt_showddatasegment)
1220 #endif /* !defined(NDEBUG) */
1222 /* release memory */
1224 dump_release(dumpsize);
1226 /* return native stub code */
1232 /* codegen_disassemble_nativestub **********************************************
1234 Disassembles the generated native stub.
1236 *******************************************************************************/
1238 #if defined(ENABLE_DISASSEMBLER)
1239 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
1241 printf("Native stub: ");
1242 utf_fprint_printable_ascii_classname(stdout, m->class->name);
1244 utf_fprint_printable_ascii(stdout, m->name);
1245 utf_fprint_printable_ascii(stdout, m->descriptor);
1246 printf("\n\nLength: %d\n\n", (s4) (end - start));
1248 DISASSEMBLE(start, end);
1253 /* codegen_stub_builtin_enter **************************************************
1255 Prepares the stuff required for a builtin function call:
1257 - adds a stackframe info structure to the chain, for stacktraces
1259 The layout of the builtin stub stackframe should look like this:
1261 +---------------------------+ <- SP (of parent Java function)
1263 +---------------------------+
1265 | stackframe info structure |
1267 +---------------------------+
1269 | arguments (if any) |
1271 +---------------------------+ <- SP (native stub)
1273 *******************************************************************************/
1275 void codegen_stub_builtin_enter(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
1277 stackframeinfo *sfi;
1279 /* get data structures from stack */
1281 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1283 /* add a stackframeinfo to the chain */
1285 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1287 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1288 /* set the native world flag */
1290 THREADOBJECT->flags |= THREAD_FLAG_IN_NATIVE;
1295 /* codegen_stub_builtin_exit ***************************************************
1297 Removes the stuff required for a builtin function call.
1299 *******************************************************************************/
1301 void codegen_stub_builtin_exit(u1 *datasp)
1303 stackframeinfo *sfi;
1304 stackframeinfo **psfi;
1306 /* get data structures from stack */
1308 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1310 /* remove current stackframeinfo from chain */
1312 psfi = &STACKFRAMEINFO;
1316 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1317 /* clear the native world flag */
1319 THREADOBJECT->flags &= ~THREAD_FLAG_IN_NATIVE;
1324 /* codegen_start_native_call ***************************************************
1326 Prepares the stuff required for a native (JNI) function call:
1328 - adds a stackframe info structure to the chain, for stacktraces
1329 - prepares the local references table on the stack
1331 The layout of the native stub stackframe should look like this:
1333 +---------------------------+ <- SP (of parent Java function)
1335 +---------------------------+
1337 | stackframe info structure |
1339 +---------------------------+
1341 | local references table |
1343 +---------------------------+
1345 | arguments (if any) |
1347 +---------------------------+ <- SP (native stub)
1349 *******************************************************************************/
1351 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
1353 stackframeinfo *sfi;
1354 localref_table *lrt;
1356 /* get data structures from stack */
1358 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1359 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1360 sizeof(localref_table));
1362 /* add a stackframeinfo to the chain */
1364 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1366 #if defined(ENABLE_JAVASE)
1367 /* add current JNI local references table to this thread */
1369 lrt->capacity = LOCALREFTABLE_CAPACITY;
1371 lrt->localframes = 1;
1372 lrt->prev = LOCALREFTABLE;
1374 /* clear the references array (memset is faster the a for-loop) */
1376 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1378 LOCALREFTABLE = lrt;
1381 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1382 /* set the native world flag */
1384 THREADOBJECT->flags |= THREAD_FLAG_IN_NATIVE;
1389 /* codegen_finish_native_call **************************************************
1391 Removes the stuff required for a native (JNI) function call.
1392 Additionally it checks for an exceptions and in case, get the
1393 exception object and clear the pointer.
1395 *******************************************************************************/
1397 java_objectheader *codegen_finish_native_call(u1 *datasp)
1399 stackframeinfo *sfi;
1400 stackframeinfo **psfi;
1401 #if defined(ENABLE_JAVASE)
1402 localref_table *lrt;
1403 localref_table *plrt;
1406 java_objectheader *e;
1408 /* get data structures from stack */
1410 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1412 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1413 /* clear the native world flag */
1415 THREADOBJECT->flags &= ~THREAD_FLAG_IN_NATIVE;
1418 /* remove current stackframeinfo from chain */
1420 psfi = &STACKFRAMEINFO;
1424 #if defined(ENABLE_JAVASE)
1425 /* release JNI local references tables for this thread */
1427 lrt = LOCALREFTABLE;
1429 /* release all current local frames */
1431 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1432 /* get previous frame */
1436 /* Clear all reference entries (only for tables allocated on
1439 if (localframes > 1)
1440 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1444 /* set new local references table */
1449 /* now store the previous local frames in the thread structure */
1451 LOCALREFTABLE = lrt;
1454 /* get the exception and return it */
1456 e = exceptions_get_and_clear_exception();
1462 /* removecompilerstub **********************************************************
1464 Deletes a compilerstub from memory (simply by freeing it).
1466 *******************************************************************************/
1468 void removecompilerstub(u1 *stub)
1470 /* pass size 1 to keep the intern function happy */
1472 CFREE((void *) stub, 1);
1476 /* removenativestub ************************************************************
1478 Removes a previously created native-stub from memory.
1480 *******************************************************************************/
1482 void removenativestub(u1 *stub)
1484 /* pass size 1 to keep the intern function happy */
1486 CFREE((void *) stub, 1);
1490 /* codegen_reg_of_var **********************************************************
1492 This function determines a register, to which the result of an
1493 operation should go, when it is ultimatively intended to store the
1494 result in pseudoregister v. If v is assigned to an actual
1495 register, this register will be returned. Otherwise (when v is
1496 spilled) this function returns tempregnum. If not already done,
1497 regoff and flags are set in the stack location.
1499 On ARM we have to check if a long/double variable is splitted
1500 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1501 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1502 cases. (michi 2005/07/24)
1504 *******************************************************************************/
1506 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
1510 /* Do we have to generate a conditional move? Yes, then always
1511 return the temporary register. The real register is identified
1512 during the store. */
1514 if (opcode & ICMD_CONDITION_MASK)
1518 if (!(v->flags & INMEMORY)) {
1519 #if defined(__ARM__) && defined(__ARMEL__)
1520 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
1521 return PACK_REGS(GET_LOW_REG(v->vv.regoff),
1522 GET_HIGH_REG(tempregnum));
1524 #if defined(__ARM__) && defined(__ARMEB__)
1525 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
1526 return PACK_REGS(GET_LOW_REG(tempregnum),
1527 GET_HIGH_REG(v->vv.regoff));
1529 return v->vv.regoff;
1532 #if defined(ENABLE_STATISTICS)
1534 count_spills_read++;
1540 /* codegen_reg_of_dst **********************************************************
1542 This function determines a register, to which the result of an
1543 operation should go, when it is ultimatively intended to store the
1544 result in iptr->dst.var. If dst.var is assigned to an actual
1545 register, this register will be returned. Otherwise (when it is
1546 spilled) this function returns tempregnum. If not already done,
1547 regoff and flags are set in the stack location.
1549 On ARM we have to check if a long/double variable is splitted
1550 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1551 register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
1552 cases. (michi 2005/07/24)
1554 *******************************************************************************/
1556 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1558 return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
1562 #if defined(ENABLE_THREADS)
1563 void codegen_threadcritrestart(codegendata *cd, int offset)
1565 cd->threadcritcurrent.mcoderestart = offset;
1569 void codegen_threadcritstart(codegendata *cd, int offset)
1571 cd->threadcritcurrent.mcodebegin = offset;
1575 void codegen_threadcritstop(codegendata *cd, int offset)
1577 cd->threadcritcurrent.next = cd->threadcrit;
1578 cd->threadcritcurrent.mcodeend = offset;
1579 cd->threadcrit = DNEW(codegen_critical_section_t);
1580 *(cd->threadcrit) = cd->threadcritcurrent;
1581 cd->threadcritcount++;
1587 * These are local overrides for various environment variables in Emacs.
1588 * Please do not remove this and leave it at the end of the file, where
1589 * Emacs will automagically detect them.
1590 * ---------------------------------------------------------------------
1593 * indent-tabs-mode: t
1597 * vim:noexpandtab:sw=4:ts=4: