1 /* src/vm/jit/codegen.inc - architecture independent code generator
3 Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4 R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5 C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6 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., 59 Temple Place - Suite 330, Boston, MA
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Reinhard Grafl
30 Changes: Christian Thalinger
33 All functions assume the following code area / data area layout:
37 | code area | code area grows to higher addresses
39 +-----------+ <-- start of procedure
41 | data area | data area grows to lower addresses
45 The functions first write into a temporary code/data area allocated by
46 "codegen_init". "codegen_finish" copies the code and data area into permanent
47 memory. All functions writing values into the data area return the offset
48 relative the begin of the code area (start of procedure).
50 $Id: codegen.inc 3474 2005-10-21 12:02:40Z twisti $
61 #include "mm/memory.h"
62 #include "toolbox/avl.h"
63 #include "toolbox/logging.h"
64 #include "native/jni.h"
65 #include "native/native.h"
67 #if defined(USE_THREADS)
68 # if defined(NATIVE_THREADS)
69 # include "threads/native/threads.h"
71 # include "threads/green/threads.h"
75 #include "vm/exceptions.h"
76 #include "vm/method.h"
77 #include "vm/options.h"
78 #include "vm/statistics.h"
79 #include "vm/jit/codegen.inc.h"
80 #include "vm/jit/disass.h"
81 #include "vm/jit/jit.h"
82 #include "vm/jit/stacktrace.h"
85 /* in this tree we store all method addresses *********************************/
87 #if defined(__I386__) || defined(__X86_64__) || defined(__INTRP__)
88 static struct avl_table *methodtree = NULL;
89 static int methodtree_comparator(const void *pc, const void *element,
94 /* codegen_init ****************************************************************
98 *******************************************************************************/
100 void codegen_init(void)
102 #if defined(__I386__) || defined(__X86_64__) || defined(__INTRP__)
103 /* this tree is global, not method specific */
106 #if !defined(__INTRP__)
107 methodtree_element *mte;
110 methodtree = avl_create(methodtree_comparator, NULL, NULL);
112 #if !defined(__INTRP__)
113 /* insert asm_calljavafunction */
115 mte = NEW(methodtree_element);
117 mte->startpc = (functionptr) asm_calljavafunction;
118 mte->endpc = (functionptr) ((ptrint) asm_calljavafunction2 - 1);
120 avl_insert(methodtree, mte);
122 /* insert asm_calljavafunction2 */
124 mte = NEW(methodtree_element);
126 mte->startpc = (functionptr) asm_calljavafunction2;
127 mte->endpc = (functionptr) ((ptrint) asm_call_jit_compiler - 1);
129 avl_insert(methodtree, mte);
130 #endif /* !defined(__INTRP__) */
136 /* codegen_setup **************************************************************
138 allocates and initialises code area, data area and references
140 *******************************************************************************/
142 void codegen_setup(methodinfo *m, codegendata *cd, t_inlining_globals *id)
144 cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
145 cd->mcodesize = MCODEINITSIZE;
147 cd->dsegtop = DMNEW(u1, DSEGINITSIZE);
148 cd->dsegsize = DSEGINITSIZE;
149 cd->dsegtop += cd->dsegsize;
152 cd->jumpreferences = NULL;
153 cd->datareferences = NULL;
154 cd->xboundrefs = NULL;
155 cd->xnullrefs = NULL;
156 cd->xcastrefs = NULL;
157 cd->xstorerefs = NULL;
159 cd->xexceptionrefs = NULL;
160 cd->patchrefs = NULL;
162 cd->linenumberreferences = NULL;
163 cd->linenumbertablesizepos = 0;
164 cd->linenumbertablestartpos = 0;
165 cd->linenumbertab = 0;
168 cd->exceptiontable = 0;
169 cd->exceptiontablelength = 0;
171 if (useinlining && id) {
172 if (id->cumextablelength > 0) {
173 cd->exceptiontablelength = id->cumextablelength;
175 DMNEW(exceptiontable, id->cumextablelength + 1);
178 } else if (id && (id->method->exceptiontablelength > 0)) {
179 cd->exceptiontablelength = m->exceptiontablelength;
180 cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
184 cd->maxstack = id->cummaxstack;
185 cd->maxlocals = id->cumlocals;
187 cd->maxstack = m->maxstack;
188 cd->maxlocals = m->maxlocals;
191 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
192 cd->threadcritcurrent.next = NULL;
193 cd->threadcritcount = 0;
198 /* codegen_free ****************************************************************
200 Releases temporary code and data area.
202 *******************************************************************************/
204 void codegen_free(methodinfo *m, codegendata *cd)
209 MFREE(cd->mcodebase, u1, cd->mcodesize);
210 cd->mcodebase = NULL;
214 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
222 /* codegen_close ***************************************************************
226 *******************************************************************************/
228 void codegen_close(void)
230 /* TODO: release avl tree on i386 and x86_64 */
234 /* codegen_increase ************************************************************
238 *******************************************************************************/
240 static s4 *codegen_increase(codegendata *cd, u1 *mcodeptr)
244 /* save old mcodebase pointer */
246 oldmcodebase = cd->mcodebase;
248 /* reallocate to new, doubled memory */
250 cd->mcodebase = DMREALLOC(cd->mcodebase,
255 cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
257 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__)
258 /* adjust the pointer to the last patcher position */
260 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
263 /* return the new mcodeptr */
265 return (s4 *) (cd->mcodebase + (mcodeptr - oldmcodebase));
269 /* desg_increase ***************************************************************
273 *******************************************************************************/
275 static void dseg_increase(codegendata *cd)
279 newstorage = DMNEW(u1, cd->dsegsize * 2);
281 MCOPY(newstorage + cd->dsegsize, cd->dsegtop - cd->dsegsize, u1,
284 cd->dsegtop = newstorage;
286 cd->dsegtop += cd->dsegsize;
290 static s4 dseg_adds4_increase(codegendata *cd, s4 value)
294 *((s4 *) (cd->dsegtop - cd->dseglen)) = value;
296 return -(cd->dseglen);
300 static s4 dseg_adds4(codegendata *cd, s4 value)
305 dataptr = (s4 *) (cd->dsegtop - cd->dseglen);
307 if (cd->dseglen > cd->dsegsize)
308 return dseg_adds4_increase(cd, value);
312 return -(cd->dseglen);
316 #if !defined(__I386__) && !defined(__POWERPC__)
317 static s4 dseg_adds8_increase(codegendata *cd, s8 value)
321 *((s8 *) (cd->dsegtop - cd->dseglen)) = value;
323 return -(cd->dseglen);
327 static s4 dseg_adds8(codegendata *cd, s8 value)
331 cd->dseglen = ALIGN(cd->dseglen + 8, 8);
332 dataptr = (s8 *) (cd->dsegtop - cd->dseglen);
334 if (cd->dseglen > cd->dsegsize)
335 return dseg_adds8_increase(cd, value);
339 return -(cd->dseglen);
344 #if !defined(__XDSPCORE__)
345 static s4 dseg_addfloat_increase(codegendata *cd, float value)
349 *((float *) (cd->dsegtop - cd->dseglen)) = value;
351 return -(cd->dseglen);
355 static s4 dseg_addfloat(codegendata *cd, float value)
360 dataptr = (float *) (cd->dsegtop - cd->dseglen);
362 if (cd->dseglen > cd->dsegsize)
363 return dseg_addfloat_increase(cd, value);
367 return -(cd->dseglen);
371 static s4 dseg_adddouble_increase(codegendata *cd, double value)
375 *((double *) (cd->dsegtop - cd->dseglen)) = value;
377 return -(cd->dseglen);
381 static s4 dseg_adddouble(codegendata *cd, double value)
385 cd->dseglen = ALIGN(cd->dseglen + 8, 8);
386 dataptr = (double *) (cd->dsegtop - cd->dseglen);
388 if (cd->dseglen > cd->dsegsize)
389 return dseg_adddouble_increase(cd, value);
393 return -(cd->dseglen);
395 #endif /* !defined(__XDSPCORE__) */
398 static void dseg_addtarget(codegendata *cd, basicblock *target)
403 jr->tablepos = dseg_addaddress(cd, NULL);
405 jr->next = cd->jumpreferences;
406 cd->jumpreferences = jr;
410 #if defined(__I386__) || defined(__X86_64__)
411 static void dseg_adddata(codegendata *cd, u1 *ptr)
416 dr->pos = (u1 *) (ptr - cd->mcodebase);
417 dr->next = cd->datareferences;
418 cd->datareferences = dr;
423 /* dseg_addlinenumbertablesize *************************************************
427 *******************************************************************************/
429 static void dseg_addlinenumbertablesize(codegendata *cd)
431 #if SIZEOF_VOID_P == 8
432 /* 4-byte ALIGNMENT PADDING */
437 cd->linenumbertablesizepos = dseg_addaddress(cd, NULL);
438 cd->linenumbertablestartpos = dseg_addaddress(cd, NULL);
440 #if SIZEOF_VOID_P == 8
441 /* 4-byte ALIGNMENT PADDING */
448 static void dseg_addlinenumber(codegendata *cd, u2 linenumber, u1 *ptr)
452 lr = DNEW(linenumberref);
453 lr->linenumber = linenumber;
455 lr->targetmpc = (ptr - cd->mcodebase);
456 lr->next = cd->linenumberreferences;
457 cd->linenumberreferences = lr;
461 /* we need this function externally on i386 and x86_64, but keep the call fast
464 #if defined(__I386__) || defined(__X86_64__)
465 void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
467 static void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
472 branchpos = (u1 *) branchptr - cd->mcodebase;
474 #if !defined(__INTRP__)
475 /* The interpreter uses absolute branches, so we do branch resolving */
476 /* after the code and data segment move. */
478 /* Check if the target basicblock has already a start pc, so the jump is */
479 /* backward and we can resolve it immediately. */
481 if (target->mpc >= 0) {
482 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
489 branchref *br = DNEW(branchref);
491 br->branchpos = branchpos;
492 br->next = target->branchrefs;
493 target->branchrefs = br;
498 static void codegen_addxboundrefs(codegendata *cd, void *branchptr, s4 reg)
503 branchpos = (u1 *) branchptr - cd->mcodebase;
505 br = DNEW(branchref);
506 br->branchpos = branchpos;
508 br->next = cd->xboundrefs;
513 static void codegen_addxnullrefs(codegendata *cd, void *branchptr)
518 branchpos = (u1 *) branchptr - cd->mcodebase;
520 br = DNEW(branchref);
521 br->branchpos = branchpos;
522 br->next = cd->xnullrefs;
527 static void codegen_addxcastrefs(codegendata *cd, void *branchptr)
532 branchpos = (u1 *) branchptr - cd->mcodebase;
534 br = DNEW(branchref);
535 br->branchpos = branchpos;
536 br->next = cd->xcastrefs;
541 /* codegen_addxstorerefs *******************************************************
543 Adds an ArrayStoreException branch to the list.
545 *******************************************************************************/
547 static void codegen_addxstorerefs(codegendata *cd, void *branchptr)
552 branchpos = (u1 *) branchptr - cd->mcodebase;
554 br = DNEW(branchref);
555 br->branchpos = branchpos;
556 br->next = cd->xstorerefs;
561 /* codegen_addxdivrefs *********************************************************
563 Adds an ArithmeticException branch to the list.
565 *******************************************************************************/
567 static void codegen_addxdivrefs(codegendata *cd, void *branchptr)
572 branchpos = (u1 *) branchptr - cd->mcodebase;
574 br = DNEW(branchref);
575 br->branchpos = branchpos;
576 br->next = cd->xdivrefs;
581 static void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
586 branchpos = (u1 *) branchptr - cd->mcodebase;
588 br = DNEW(branchref);
589 br->branchpos = branchpos;
590 br->next = cd->xexceptionrefs;
591 cd->xexceptionrefs = br;
595 /* codegen_addpatchref *********************************************************
597 Adds a new patcher reference to the list of patching positions.
599 *******************************************************************************/
601 static void codegen_addpatchref(codegendata *cd, voidptr branchptr,
602 functionptr patcher, voidptr ref, s4 disp)
607 branchpos = (u1 *) branchptr - cd->mcodebase;
611 pr->branchpos = branchpos;
612 pr->patcher = patcher;
616 pr->next = cd->patchrefs;
619 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__)
620 /* On some architectures the patcher stub call instruction might
621 be longer than the actual instruction generated. On this
622 architectures we store the last patcher call position and after
623 the basic block code generation is completed, we check the range
624 and maybe generate some nop's. */
626 cd->lastmcodeptr = ((u1 *) branchptr) + PATCHER_CALL_SIZE;
631 /* codegen_createlinenumbertable ***********************************************
633 Creates a line number table in the data segment from the created
634 entries in linenumberreferences.
636 *******************************************************************************/
638 static void codegen_createlinenumbertable(codegendata *cd)
642 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
643 lr->tablepos = dseg_addaddress(cd, NULL);
645 if (cd->linenumbertab == 0)
646 cd->linenumbertab = lr->tablepos;
648 dseg_addaddress(cd, lr->linenumber);
653 #if defined(__I386__) || defined(__X86_64__) || defined(__INTRP__)
654 /* methodtree_comparator *******************************************************
658 *******************************************************************************/
660 static int methodtree_comparator(const void *pc, const void *element, void *param)
662 methodtree_element *mte;
663 methodtree_element *mtepc;
665 mte = (methodtree_element *) element;
666 mtepc = (methodtree_element *) pc;
668 /* compare both startpc and endpc of pc, even if they have the same value,
669 otherwise the avl_probe sometimes thinks the element is already in the
672 if ((long) mte->startpc <= (long) mtepc->startpc &&
673 (long) mtepc->startpc <= (long) mte->endpc &&
674 (long) mte->startpc <= (long) mtepc->endpc &&
675 (long) mtepc->endpc <= (long) mte->endpc) {
678 } else if ((long) mtepc->startpc < (long) mte->startpc) {
687 /* codegen_insertmethod ********************************************************
691 *******************************************************************************/
693 void codegen_insertmethod(functionptr startpc, functionptr endpc)
695 methodtree_element *mte;
697 #if defined(USE_THREADS)
698 #if defined(NATIVE_THREADS)
703 mte = NEW(methodtree_element);
704 mte->startpc = startpc;
707 if (avl_insert(methodtree, mte)) {
708 #if defined(USE_THREADS)
709 #if defined(NATIVE_THREADS)
714 throw_cacao_exception_exit(string_java_lang_InternalError,
718 #if defined(USE_THREADS)
719 #if defined(NATIVE_THREADS)
726 /* codegen_findmethod **********************************************************
730 *******************************************************************************/
732 functionptr codegen_findmethod(functionptr pc)
734 methodtree_element *mtepc;
735 methodtree_element *mte;
737 #if defined(USE_THREADS)
738 #if defined(NATIVE_THREADS)
743 mtepc = NEW(methodtree_element);
747 mte = avl_find(methodtree, mtepc);
749 FREE(mtepc, methodtree_element);
752 #if defined(USE_THREADS)
753 #if defined(NATIVE_THREADS)
757 printf("Cannot find Java function at %p\n", (void *) (ptrint) pc);
759 throw_cacao_exception_exit(string_java_lang_InternalError,
760 "Cannot find Java function at %p", pc);
763 #if defined(USE_THREADS)
764 #if defined(NATIVE_THREADS)
771 #endif /* defined(__I386__) || defined(__X86_64__) || defined(__INTRP__) */
774 /* codegen_finish **************************************************************
776 Finishes the code generation. A new memory, large enough for both
777 data and code, is allocated and data and code are copied together
778 to their final layout, unresolved jumps are resolved, ...
780 *******************************************************************************/
782 static void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
789 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
790 extralen = sizeof(threadcritnode) * cd->threadcritcount;
795 #if defined(STATISTICS)
797 count_code_len += mcodelen;
798 count_data_len += cd->dseglen;
802 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
803 alignedlen = ALIGN(mcodelen, MAX_ALIGN) + cd->dseglen;
805 /* allocate new memory */
807 m->mcodelength = mcodelen + cd->dseglen;
808 m->mcode = (functionptr) (ptrint) CNEW(u1, alignedlen + extralen);
810 /* copy data and code to their new location */
812 MCOPY((void *) (ptrint) m->mcode, cd->dsegtop - cd->dseglen, u1,
814 MCOPY((void *) ((ptrint) m->mcode + cd->dseglen), cd->mcodebase, u1,
817 m->entrypoint = epoint = (functionptr) ((ptrint) m->mcode + cd->dseglen);
819 /* jump table resolving */
821 jr = cd->jumpreferences;
823 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
824 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
828 /* line number table resolving */
833 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
835 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
836 (functionptr) ((ptrint) epoint + (ptrint) lr->targetmpc);
839 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
840 (functionptr) ((ptrint) epoint + cd->linenumbertab);
842 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
845 #if defined(__I386__) || defined(__X86_64__) || defined(__INTRP__)
846 /* add method into methodtree to find the entrypoint */
848 codegen_insertmethod(m->entrypoint,
849 (functionptr) ((ptrint) m->entrypoint + mcodelen));
852 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__)
856 /* data segment references resolving */
858 dr = cd->datareferences;
860 *((functionptr *) ((ptrint) epoint + (ptrint) dr->pos -
861 SIZEOF_VOID_P)) = epoint;
867 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
869 threadcritnode *n = (threadcritnode *) ((ptrint) m->mcode + alignedlen);
871 threadcritnodetemp *nt = cd->threadcrit;
873 for (i = 0; i < cd->threadcritcount; i++) {
874 n->mcodebegin = (u1 *) (ptrint) m->mcode + nt->mcodebegin;
875 n->mcodeend = (u1 *) (ptrint) m->mcode + nt->mcodeend;
876 n->mcoderestart = (u1 *) (ptrint) m->mcode + nt->mcoderestart;
877 thread_registercritical(n);
886 void dseg_display(methodinfo *m, codegendata *cd)
891 s4ptr = (s4 *) (ptrint) m->mcode;
893 printf(" --- dump of datasegment\n");
894 for (i = cd->dseglen; i > 0 ; i -= 4) {
895 #if SIZEOF_VOID_P == 8
896 printf("0x%016lx: -%6x (%6d): %8x\n",
897 (ptrint) s4ptr, i, i, (s4) *s4ptr);
899 printf("0x%08x: -%6x (%6d): %8x\n",
900 (ptrint) s4ptr, i, i, (s4) *s4ptr);
905 printf(" --- begin of data segment: %p\n", (void *) s4ptr);
910 /* codegen_createnativestub ****************************************************
912 Wrapper for createnativestub.
914 *******************************************************************************/
916 functionptr codegen_createnativestub(functionptr f, methodinfo *m)
920 t_inlining_globals *id;
926 /* mark dump memory */
928 dumpsize = dump_size();
930 cd = DNEW(codegendata);
931 rd = DNEW(registerdata);
932 id = DNEW(t_inlining_globals);
934 /* setup code generation stuff */
936 inlining_setup(m, id);
937 #if !defined(__INTRP__)
938 reg_setup(m, rd, id);
940 codegen_setup(m, cd, id);
942 /* create new method descriptor with additional native parameters */
945 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
947 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
948 md->paramcount * sizeof(typedesc) +
949 nativeparams * sizeof(typedesc));
951 nmd->paramcount = md->paramcount + nativeparams;
953 nmd->params = DMNEW(paramdesc, nmd->paramcount);
955 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
957 if (m->flags & ACC_STATIC)
958 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
960 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
965 /* generate the code */
967 m->entrypoint = createnativestub(f, m, cd, rd, nmd);
969 #if defined(STATISTICS)
971 count_nstub_len += m->mcodelength;
974 /* disassemble native stub */
976 if (opt_shownativestub) {
977 codegen_disassemble_nativestub(m,
978 (u1 *) (ptrint) m->entrypoint,
979 (u1 *) (ptrint) m->entrypoint + (m->mcodelength - cd->dseglen));
981 /* show data segment */
983 if (opt_showddatasegment)
989 dump_release(dumpsize);
991 /* return native stub entry point */
993 return m->entrypoint;
997 /* codegen_disassemble_nativestub **********************************************
999 Disassembles the generated native stub.
1001 *******************************************************************************/
1003 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
1005 printf("Native stub: ");
1006 utf_fprint_classname(stdout, m->class->name);
1008 utf_fprint(stdout, m->name);
1009 utf_fprint(stdout, m->descriptor);
1010 printf("\n\nLength: %d\n\n", (s4) (end - start));
1012 disassemble(start, end);
1016 /* codegen_start_native_call ***************************************************
1018 Prepares the stuff required for a native (JNI) function call:
1020 - adds a stackframe info structure to the chain, for stacktraces
1021 - prepares the local references table on the stack
1023 The layout of the native stub stackframe should look like this:
1025 +---------------------------+ <- SP (of parent Java function)
1027 +---------------------------+
1029 | stackframe info structure |
1031 +---------------------------+
1033 | local references table |
1035 +---------------------------+
1037 | arguments (if any) |
1039 +---------------------------+ <- SP (native stub)
1041 *******************************************************************************/
1043 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, functionptr ra)
1045 stackframeinfo *sfi;
1046 localref_table *lrt;
1049 /* get data structures from stack */
1051 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1052 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1053 sizeof(localref_table));
1055 /* get thread info */
1059 /* add a stackframeinfo to the chain */
1061 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1063 /* add current JNI local references table to this thread */
1065 lrt->capacity = LOCALREFTABLE_CAPACITY;
1067 lrt->localframes = 1;
1068 lrt->prev = info->_localref_table;
1070 /* clear the references array (memset is faster the a for-loop) */
1072 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1074 info->_localref_table = lrt;
1078 /* codegen_finish_native_call **************************************************
1080 Removes the stuff required for a native (JNI) function call.
1082 *******************************************************************************/
1084 void codegen_finish_native_call(u1 *datasp)
1086 stackframeinfo *sfi;
1087 localref_table *lrt;
1091 /* get data structures from stack */
1093 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1094 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1095 sizeof(localref_table));
1097 /* get thread info */
1101 /* remove current stackframeinfo from chain */
1103 info->_stackframeinfo = sfi->prev;
1105 /* release JNI local references tables for this thread */
1107 lrt = info->_localref_table;
1109 /* got through all current local frames */
1111 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1115 /* now store the previous local frames in the thread structure */
1117 info->_localref_table = lrt;
1121 /* removecompilerstub **********************************************************
1123 Deletes a compilerstub from memory (simply by freeing it).
1125 *******************************************************************************/
1127 void removecompilerstub(functionptr stub)
1129 /* pass size 1 to keep the intern function happy */
1131 CFREE((void *) (ptrint) stub, 1);
1135 /* removenativestub ************************************************************
1137 Removes a previously created native-stub from memory.
1139 *******************************************************************************/
1141 void removenativestub(functionptr stub)
1143 /* pass size 1 to keep the intern function happy */
1145 CFREE((void *) (ptrint) stub, 1);
1150 This function determines a register, to which the result of an operation
1151 should go, when it is ultimatively intended to store the result in
1153 If v is assigned to an actual register, this register will be returned.
1154 Otherwise (when v is spilled) this function returns tempregnum.
1155 If not already done, regoff and flags are set in the stack location.
1157 /* On ARM we have to check if a long/double variable is splitted
1158 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual register
1159 of v for LOW_REG and the tempregnum for HIGH_REG in such cases.
1163 static int reg_of_var(registerdata *rd, stackptr v, int tempregnum)
1167 switch (v->varkind) {
1169 if (!(v->flags & INMEMORY))
1174 var = &(rd->interfaces[v->varnum][v->type]);
1175 v->regoff = var->regoff;
1176 if (!(var->flags & INMEMORY))
1177 return(var->regoff);
1181 var = &(rd->locals[v->varnum][v->type]);
1182 v->regoff = var->regoff;
1183 if (!(var->flags & INMEMORY)) {
1184 #if defined(__ARM__) && defined(__ARMEL__)
1185 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
1186 return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
1188 #if defined(__ARM__) && defined(__ARMEB__)
1189 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
1190 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
1192 return(var->regoff);
1197 if (!(v->flags & INMEMORY)) {
1198 #if defined(__ARM__) && defined(__ARMEL__)
1199 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
1200 return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
1202 #if defined(__ARM__) && defined(__ARMEB__)
1203 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
1204 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
1212 count_spills_read++;
1214 v->flags |= INMEMORY;
1219 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1220 static void codegen_threadcritrestart(codegendata *cd, int offset)
1222 cd->threadcritcurrent.mcoderestart = offset;
1226 static void codegen_threadcritstart(codegendata *cd, int offset)
1228 cd->threadcritcurrent.mcodebegin = offset;
1232 static void codegen_threadcritstop(codegendata *cd, int offset)
1234 cd->threadcritcurrent.next = cd->threadcrit;
1235 cd->threadcritcurrent.mcodeend = offset;
1236 cd->threadcrit = DNEW(threadcritnodetemp);
1237 *(cd->threadcrit) = cd->threadcritcurrent;
1238 cd->threadcritcount++;
1244 * These are local overrides for various environment variables in Emacs.
1245 * Please do not remove this and leave it at the end of the file, where
1246 * Emacs will automagically detect them.
1247 * ---------------------------------------------------------------------
1250 * indent-tabs-mode: t