* src/vm/jit/codegen-common.c (codegen_setup): Fixed compiler
[cacao.git] / src / vm / jit / codegen-common.c
1 /* src/vm/jit/codegen-common.c - architecture independent code generator stuff
2
3    Copyright (C) 1996-2005, 2006 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
7
8    This file is part of CACAO.
9
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.
14
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.
19
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
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Reinhard Grafl
28             Andreas  Krall
29
30    Changes: Christian Thalinger
31             Joseph Wenninger
32                         Edwin Steiner
33
34    All functions assume the following code area / data area layout:
35
36    +-----------+
37    |           |
38    | code area | code area grows to higher addresses
39    |           |
40    +-----------+ <-- start of procedure
41    |           |
42    | data area | data area grows to lower addresses
43    |           |
44    +-----------+
45
46    The functions first write into a temporary code/data area allocated by
47    "codegen_init". "codegen_finish" copies the code and data area into permanent
48    memory. All functions writing values into the data area return the offset
49    relative the begin of the code area (start of procedure).    
50
51    $Id: codegen-common.c 4775 2006-04-14 11:57:04Z twisti $
52
53 */
54
55
56 #include "config.h"
57
58 #include <assert.h>
59 #include <string.h>
60
61 #include "vm/types.h"
62
63 #if defined(ENABLE_JIT)
64 /* this is required for gen_resolvebranch and PATCHER_CALL_SIZE */
65 # include "codegen.h"
66 #endif
67
68 #if defined(__ARM__)
69 /* this is required for REG_SPLIT */
70 # include "md-abi.h"
71 #endif
72
73 #include "mm/memory.h"
74 #include "toolbox/avl.h"
75 #include "toolbox/logging.h"
76 #include "native/jni.h"
77 #include "native/native.h"
78
79 #if defined(USE_THREADS)
80 # if defined(NATIVE_THREADS)
81 #  include "threads/native/threads.h"
82 # else
83 #  include "threads/green/threads.h"
84 # endif
85 #endif
86
87 #include "vm/exceptions.h"
88 #include "vm/method.h"
89 #include "vm/options.h"
90 #include "vm/statistics.h"
91 #include "vm/stringlocal.h"
92 #include "vm/jit/asmpart.h"
93 #include "vm/jit/codegen-common.h"
94
95 #if defined(ENABLE_DISASSEMBLER)
96 # include "vm/jit/disass.h"
97 #endif
98
99 #include "vm/jit/dseg.h"
100 #include "vm/jit/jit.h"
101 #include "vm/jit/stacktrace.h"
102 #include "vm/jit/replace.h"
103
104
105 /* in this tree we store all method addresses *********************************/
106
107 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
108 static avl_tree *methodtree = NULL;
109 static s4 methodtree_comparator(const void *pc, const void *element);
110 #endif
111
112
113 /* codegen_init ****************************************************************
114
115    TODO
116
117 *******************************************************************************/
118
119 void codegen_init(void)
120 {
121 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
122         /* this tree is global, not method specific */
123
124         if (!methodtree) {
125 #if defined(ENABLE_JIT)
126                 methodtree_element *mte;
127 #endif
128
129                 methodtree = avl_create(&methodtree_comparator);
130
131 #if defined(ENABLE_JIT)
132                 /* insert asm_vm_call_method */
133
134                 mte = NEW(methodtree_element);
135
136                 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
137                 mte->endpc   = (u1 *) ((ptrint) asm_call_jit_compiler - 1);
138
139                 avl_insert(methodtree, mte);
140 #endif /* defined(ENABLE_JIT) */
141         }
142 #endif /* defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
143 }
144
145
146 /* codegen_setup ***************************************************************
147
148    Allocates and initialises code area, data area and references.
149
150 *******************************************************************************/
151
152 void codegen_setup(jitdata *jd)
153 {
154         methodinfo  *m;
155         codegendata *cd;
156
157         /* get required compiler data */
158
159         m  = jd->m;
160         cd = jd->cd;
161
162         cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
163         cd->mcodeend  = cd->mcodebase + MCODEINITSIZE;
164         cd->mcodesize = MCODEINITSIZE;
165
166         /* initialize mcode variables */
167
168 #if defined(__I386__) || defined(__X86_64__)    
169         cd->mcodeptr = cd->mcodebase;
170 #else
171         cd->mcodeptr = (u4 *) cd->mcodebase;
172 #endif
173
174         cd->lastmcodeptr = cd->mcodebase;
175
176 #if defined(ENABLE_INTRP)
177         /* native dynamic superinstructions variables */
178
179         if (opt_intrp) {
180                 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
181                 cd->ncodesize = NCODEINITSIZE;
182
183                 /* initialize ncode variables */
184         
185                 cd->ncodeptr = cd->ncodebase;
186
187                 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
188                 cd->superstarts = NULL;
189         }
190 #endif
191         
192         cd->dsegtop = DMNEW(u1, DSEGINITSIZE);
193         cd->dsegsize = DSEGINITSIZE;
194         cd->dsegtop += cd->dsegsize;
195         cd->dseglen = 0;
196
197         cd->jumpreferences = NULL;
198
199 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
200         cd->datareferences = NULL;
201 #endif
202
203         cd->exceptionrefs  = NULL;
204         cd->patchrefs      = NULL;
205
206         cd->linenumberreferences = NULL;
207         cd->linenumbertablesizepos = 0;
208         cd->linenumbertablestartpos = 0;
209         cd->linenumbertab = 0;
210         
211         cd->method = m;
212         cd->exceptiontable = 0;
213         cd->exceptiontablelength = 0;
214
215         if (m->exceptiontablelength > 0) {
216                 cd->exceptiontablelength = m->exceptiontablelength;
217                 cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
218         }
219
220         cd->maxstack = m->maxstack;
221         cd->maxlocals = m->maxlocals;
222
223 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
224         cd->threadcritcurrent.next = NULL;
225         cd->threadcritcount = 0;
226 #endif
227 }
228
229
230 /* codegen_close ***************************************************************
231
232    TODO
233
234 *******************************************************************************/
235
236 void codegen_close(void)
237 {
238         /* TODO: release avl tree on i386 and x86_64 */
239 }
240
241
242 /* codegen_increase ************************************************************
243
244    Doubles code area.
245
246 *******************************************************************************/
247
248 s4 *codegen_increase(codegendata *cd, u1 *mcodeptr)
249 {
250         u1 *oldmcodebase;
251
252         /* save old mcodebase pointer */
253
254         oldmcodebase = cd->mcodebase;
255
256         /* reallocate to new, doubled memory */
257
258         cd->mcodebase = DMREALLOC(cd->mcodebase,
259                                                           u1,
260                                                           cd->mcodesize,
261                                                           cd->mcodesize * 2);
262         cd->mcodesize *= 2;
263         cd->mcodeend   = cd->mcodebase + cd->mcodesize;
264
265 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
266         /* adjust the pointer to the last patcher position */
267
268         if (cd->lastmcodeptr != NULL)
269                 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
270 #endif
271
272         /* return the new mcodeptr */
273
274         return (s4 *) (cd->mcodebase + (mcodeptr - oldmcodebase));
275 }
276
277
278 /* codegen_ncode_increase ******************************************************
279
280    Doubles code area.
281
282 *******************************************************************************/
283
284 #if defined(ENABLE_INTRP)
285 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
286 {
287         u1 *oldncodebase;
288
289         /* save old ncodebase pointer */
290
291         oldncodebase = cd->ncodebase;
292
293         /* reallocate to new, doubled memory */
294
295         cd->ncodebase = DMREALLOC(cd->ncodebase,
296                                                           u1,
297                                                           cd->ncodesize,
298                                                           cd->ncodesize * 2);
299         cd->ncodesize *= 2;
300
301         /* return the new ncodeptr */
302
303         return (cd->ncodebase + (ncodeptr - oldncodebase));
304 }
305 #endif
306
307
308 void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
309 {
310         s4 branchpos;
311
312         branchpos = (u1 *) branchptr - cd->mcodebase;
313
314 #if defined(ENABLE_JIT)
315         /* Check if the target basicblock has already a start pc, so the
316            jump is backward and we can resolve it immediately. */
317
318         /* The interpreter uses absolute branches, so we do branch
319            resolving after the code and data segment move. */
320
321         if (target->mpc >= 0
322 # if defined(ENABLE_INTRP)
323                 && !opt_intrp
324 # endif
325                 )
326         {
327                 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
328                                                   branchpos,
329                                                   target->mpc);
330
331         } else
332 #endif
333         {
334                 branchref *br = DNEW(branchref);
335
336                 br->branchpos = branchpos;
337                 br->next      = target->branchrefs;
338
339                 target->branchrefs = br;
340         }
341 }
342
343
344 /* codegen_add_exception_ref ***************************************************
345
346    Adds an exception branch to the list.
347
348 *******************************************************************************/
349
350 static void codegen_add_exception_ref(codegendata *cd, void *branchptr, s4 reg,
351                                                                           functionptr function)
352 {
353         s4            branchpos;
354         exceptionref *eref;
355
356         branchpos = (u1 *) branchptr - cd->mcodebase;
357
358         eref = DNEW(exceptionref);
359
360         eref->branchpos = branchpos;
361         eref->reg       = reg;
362         eref->function  = function;
363         eref->next      = cd->exceptionrefs;
364
365         cd->exceptionrefs = eref;
366 }
367
368
369 /* codegen_add_arithmeticexception_ref *****************************************
370
371    Adds an ArithmeticException branch to the list.
372
373 *******************************************************************************/
374
375 void codegen_add_arithmeticexception_ref(codegendata *cd, void *branchptr)
376 {
377         codegen_add_exception_ref(cd, branchptr, -1,
378                                                           STACKTRACE_inline_arithmeticexception);
379 }
380
381
382 /* codegen_add_arrayindexoutofboundsexception_ref ******************************
383
384    Adds an ArrayIndexOutOfBoundsException branch to the list.
385
386 *******************************************************************************/
387
388 void codegen_add_arrayindexoutofboundsexception_ref(codegendata *cd,
389                                                                                                         void *branchptr, s4 reg)
390 {
391         codegen_add_exception_ref(cd, branchptr, reg,
392                                                           STACKTRACE_inline_arrayindexoutofboundsexception);
393 }
394
395
396 /* codegen_add_arraystoreexception_ref *****************************************
397
398    Adds an ArrayStoreException branch to the list.
399
400 *******************************************************************************/
401
402 void codegen_add_arraystoreexception_ref(codegendata *cd, void *branchptr)
403 {
404         codegen_add_exception_ref(cd, branchptr, -1,
405                                                           STACKTRACE_inline_arraystoreexception);
406 }
407
408
409 /* codegen_add_classcastexception_ref ******************************************
410
411    Adds an ClassCastException branch to the list.
412
413 *******************************************************************************/
414
415 void codegen_add_classcastexception_ref(codegendata *cd, void *branchptr)
416 {
417         codegen_add_exception_ref(cd, branchptr, -1,
418                                                           STACKTRACE_inline_classcastexception);
419 }
420
421
422 /* codegen_add_nullpointerexception_ref ****************************************
423
424    Adds an NullPointerException branch to the list.
425
426 *******************************************************************************/
427
428 void codegen_add_nullpointerexception_ref(codegendata *cd, void *branchptr)
429 {
430         codegen_add_exception_ref(cd, branchptr, -1,
431                                                           STACKTRACE_inline_nullpointerexception);
432 }
433
434
435 /* codegen_add_fillinstacktrace_ref ********************************************
436
437    Adds a fillInStackTrace branch to the list.
438
439 *******************************************************************************/
440
441 void codegen_add_fillinstacktrace_ref(codegendata *cd, void *branchptr)
442 {
443         codegen_add_exception_ref(cd, branchptr, -1,
444                                                           STACKTRACE_inline_fillInStackTrace);
445 }
446
447
448 /* codegen_addpatchref *********************************************************
449
450    Adds a new patcher reference to the list of patching positions.
451
452 *******************************************************************************/
453
454 void codegen_addpatchref(codegendata *cd, voidptr branchptr,
455                                                  functionptr patcher, voidptr ref, s4 disp)
456 {
457         patchref *pr;
458         s4        branchpos;
459
460         branchpos = (u1 *) branchptr - cd->mcodebase;
461
462         pr = DNEW(patchref);
463
464         pr->branchpos = branchpos;
465         pr->patcher   = patcher;
466         pr->ref       = ref;
467         pr->disp      = disp;
468
469         pr->next      = cd->patchrefs;
470         cd->patchrefs = pr;
471
472 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
473         /* On some architectures the patcher stub call instruction might
474            be longer than the actual instruction generated.  On this
475            architectures we store the last patcher call position and after
476            the basic block code generation is completed, we check the
477            range and maybe generate some nop's. */
478
479         cd->lastmcodeptr = ((u1 *) branchptr) + PATCHER_CALL_SIZE;
480 #endif
481 }
482
483
484 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
485 /* methodtree_comparator *******************************************************
486
487    XXX
488
489 *******************************************************************************/
490
491 static s4 methodtree_comparator(const void *pc, const void *element)
492 {
493         methodtree_element *mte;
494         methodtree_element *mtepc;
495
496         mte = (methodtree_element *) element;
497         mtepc = (methodtree_element *) pc;
498
499         /* compare both startpc and endpc of pc, even if they have the same value,
500            otherwise the avl_probe sometimes thinks the element is already in the
501            tree */
502
503         if ((long) mte->startpc <= (long) mtepc->startpc &&
504                 (long) mtepc->startpc <= (long) mte->endpc &&
505                 (long) mte->startpc <= (long) mtepc->endpc &&
506                 (long) mtepc->endpc <= (long) mte->endpc) {
507                 return 0;
508
509         } else if ((long) mtepc->startpc < (long) mte->startpc) {
510                 return -1;
511
512         } else {
513                 return 1;
514         }
515 }
516
517
518 /* codegen_insertmethod ********************************************************
519
520    XXX
521
522 *******************************************************************************/
523
524 void codegen_insertmethod(u1 *startpc, u1 *endpc)
525 {
526         methodtree_element *mte;
527
528         /* allocate new method entry */
529
530         mte = NEW(methodtree_element);
531
532         mte->startpc = startpc;
533         mte->endpc   = endpc;
534
535         /* this function does not return an error, but asserts for
536            duplicate entries */
537
538         avl_insert(methodtree, mte);
539 }
540
541
542 /* codegen_findmethod **********************************************************
543
544    XXX
545
546 *******************************************************************************/
547
548 u1 *codegen_findmethod(u1 *pc)
549 {
550         methodtree_element  mtepc;
551         methodtree_element *mte;
552
553         /* allocation of the search structure on the stack is much faster */
554
555         mtepc.startpc = pc;
556         mtepc.endpc   = pc;
557
558         mte = avl_find(methodtree, &mtepc);
559
560         if (!mte) {
561                 printf("Cannot find Java function at %p\n", (void *) (ptrint) pc);
562                 assert(0);
563
564                 throw_cacao_exception_exit(string_java_lang_InternalError,
565                                                                    "Cannot find Java function at %p", pc);
566         }
567
568         return mte->startpc;
569 }
570 #endif /* defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
571
572
573 /* codegen_finish **************************************************************
574
575    Finishes the code generation. A new memory, large enough for both
576    data and code, is allocated and data and code are copied together
577    to their final layout, unresolved jumps are resolved, ...
578
579 *******************************************************************************/
580
581 void codegen_finish(jitdata *jd, s4 mcodelen)
582 {
583         codeinfo    *code;
584         codegendata *cd;
585 #if 0
586         s4           mcodelen;
587 #endif
588 #if defined(ENABLE_INTRP)
589         s4           ncodelen;
590 #endif
591         s4           alignedmcodelen;
592         jumpref     *jr;
593         u1          *epoint;
594         s4           extralen;
595         s4           alignedlen;
596
597         /* get required compiler data */
598
599         code = jd->code;
600         cd   = jd->cd;
601
602         /* prevent compiler warning */
603
604 #if defined(ENABLE_INTRP)
605         ncodelen = 0;
606 #endif
607
608 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
609         extralen = sizeof(threadcritnode) * cd->threadcritcount;
610 #else
611         extralen = 0;
612 #endif
613
614 #if defined(ENABLE_STATISTICS)
615         if (opt_stat) {
616                 count_code_len += mcodelen;
617                 count_data_len += cd->dseglen;
618         }
619 #endif
620
621 #if 0
622         mcodelen = cd->mcodeptr - cd->mcodebase;
623 #endif
624         alignedmcodelen = ALIGN(mcodelen, MAX_ALIGN);
625
626 #if defined(ENABLE_INTRP)
627         if (opt_intrp)
628                 ncodelen = cd->ncodeptr - cd->ncodebase;
629         else {
630                 ncodelen = 0; /* avoid compiler warning */
631         }
632 #endif
633
634         cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
635         alignedlen = alignedmcodelen + cd->dseglen;
636
637 #if defined(ENABLE_INTRP)
638         if (opt_intrp) {
639                 alignedlen += ncodelen;
640         }
641 #endif
642
643         /* allocate new memory */
644
645         code->mcodelength = mcodelen + cd->dseglen;
646         code->mcode = CNEW(u1, alignedlen + extralen);
647
648         /* copy data and code to their new location */
649
650         MCOPY((void *) code->mcode, cd->dsegtop - cd->dseglen, u1, cd->dseglen);
651         MCOPY((void *) (code->mcode + cd->dseglen), cd->mcodebase, u1, mcodelen);
652
653         /* set the entrypoint of the method */
654         
655         assert(code->entrypoint == NULL);
656         code->entrypoint = epoint = (code->mcode + cd->dseglen);
657
658 #if defined(ENABLE_INTRP)
659         /* relocate native dynamic superinstruction code (if any) */
660
661         if (opt_intrp) {
662                 cd->mcodebase = code->entrypoint;
663
664                 if (ncodelen > 0) {
665                         u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
666
667                         MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
668
669                         /* flush the instruction and data caches */
670
671                         md_cacheflush(ncodebase, ncodelen);
672
673                         /* set some cd variables for dynamic_super_rerwite */
674
675                         cd->ncodebase = ncodebase;
676
677                 } else {
678                         cd->ncodebase = NULL;
679                 }
680
681                 dynamic_super_rewrite(cd);
682         }
683 #endif
684
685         /* jump table resolving */
686
687         for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
688                 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
689                         (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
690
691         /* line number table resolving */
692         {
693                 linenumberref *lr;
694                 ptrint lrtlen = 0;
695                 ptrint target;
696
697                 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
698                         lrtlen++;
699                         target = lr->targetmpc;
700                         /* if the entry contains an mcode pointer (normal case), resolve it */
701                         /* (see doc/inlining_stacktrace.txt for details)                    */
702                         if (lr->linenumber >= -2) {
703                             target += (ptrint) epoint;
704                         }
705                         *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) = 
706                                 (functionptr) target;
707                 }
708                 
709                 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
710                         (functionptr) ((ptrint) epoint + cd->linenumbertab);
711
712                 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
713         }
714
715         /* replacement point resolving */
716         {
717                 int i;
718                 rplpoint *rp;
719
720                 rp = code->rplpoints;
721                 for (i=0; i<code->rplpointcount; ++i, ++rp) {
722                         rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
723                         rp->outcode = (u1*) ((ptrint) epoint + (ptrint) rp->outcode);
724                 }
725         }
726
727 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
728         /* add method into methodtree to find the entrypoint */
729
730         codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
731 #endif
732
733
734 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
735         /* resolve data segment references */
736
737         dseg_resolve_datareferences(jd);
738 #endif
739
740
741 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
742         {
743                 threadcritnode *n = (threadcritnode *) ((ptrint) code->mcode + alignedlen);
744                 s4 i;
745                 threadcritnodetemp *nt = cd->threadcrit;
746
747                 for (i = 0; i < cd->threadcritcount; i++) {
748                         n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
749                         n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
750                         n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
751                         thread_registercritical(n);
752                         n++;
753                         nt = nt->next;
754                 }
755         }
756 #endif
757
758         /* flush the instruction and data caches */
759
760         md_cacheflush(code->mcode, code->mcodelength);
761 }
762
763
764 /* codegen_createnativestub ****************************************************
765
766    Wrapper for createnativestub.
767
768    Returns:
769        the codeinfo representing the stub code.
770
771 *******************************************************************************/
772
773 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
774 {
775         jitdata     *jd;
776         codeinfo    *code;
777         s4           dumpsize;
778         methoddesc  *md;
779         methoddesc  *nmd;       
780         s4           nativeparams;
781
782         /* mark dump memory */
783
784         dumpsize = dump_size();
785
786         jd = DNEW(jitdata);
787
788         jd->m     = m;
789         jd->cd    = DNEW(codegendata);
790         jd->rd    = DNEW(registerdata);
791
792         /* Allocate codeinfo memory from the heap as we need to keep them. */
793
794         jd->code  = code_codeinfo_new(m); /* XXX check allocation */
795
796         /* get required compiler data */
797
798         code = jd->code;
799
800         /* setup code generation stuff */
801
802 #if defined(ENABLE_JIT)
803 # if defined(ENABLE_INTRP)
804         if (!opt_intrp)
805 # endif
806                 reg_setup(jd);
807 #endif
808
809         codegen_setup(jd);
810
811         /* create new method descriptor with additional native parameters */
812
813         md = m->parseddesc;
814         nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
815         
816         nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
817                                                            md->paramcount * sizeof(typedesc) +
818                                                            nativeparams * sizeof(typedesc));
819
820         nmd->paramcount = md->paramcount + nativeparams;
821
822         nmd->params = DMNEW(paramdesc, nmd->paramcount);
823
824         nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer            */
825
826         if (m->flags & ACC_STATIC)
827                 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer              */
828
829         MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
830                   md->paramcount);
831
832 #if defined(ENABLE_JIT)
833 # if defined(ENABLE_INTRP)
834         if (!opt_intrp)
835 # endif
836                 md_param_alloc(nmd);
837 #endif
838
839         /* generate the code */
840
841 #if defined(ENABLE_JIT)
842 # if defined(ENABLE_INTRP)
843         if (opt_intrp)
844                 code->entrypoint = intrp_createnativestub(f, jd, nmd);
845         else
846 # endif
847                 code->entrypoint = createnativestub(f, jd, nmd);
848 #else
849         code->entrypoint = intrp_createnativestub(f, jd, nmd);
850 #endif
851
852 #if defined(ENABLE_STATISTICS)
853         if (opt_stat)
854                 count_nstub_len += code->mcodelength;
855 #endif
856
857 #if !defined(NDEBUG)
858         /* disassemble native stub */
859
860         if (opt_shownativestub) {
861 #if defined(ENABLE_DISASSEMBLER)
862                 codegen_disassemble_nativestub(m,
863                                                                            (u1 *) (ptrint) code->entrypoint,
864                                                                            (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
865 #endif
866
867                 /* show data segment */
868
869                 if (opt_showddatasegment)
870                         dseg_display(jd);
871         }
872 #endif /* !defined(NDEBUG) */
873
874         /* release memory */
875
876         dump_release(dumpsize);
877
878         /* return native stub code */
879
880         return code;
881 }
882
883
884 /* codegen_disassemble_nativestub **********************************************
885
886    Disassembles the generated native stub.
887
888 *******************************************************************************/
889
890 #if defined(ENABLE_DISASSEMBLER)
891 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
892 {
893         printf("Native stub: ");
894         utf_fprint_classname(stdout, m->class->name);
895         printf(".");
896         utf_fprint(stdout, m->name);
897         utf_fprint(stdout, m->descriptor);
898         printf("\n\nLength: %d\n\n", (s4) (end - start));
899
900         DISASSEMBLE(start, end);
901 }
902 #endif
903
904
905 /* codegen_start_native_call ***************************************************
906
907    Prepares the stuff required for a native (JNI) function call:
908
909    - adds a stackframe info structure to the chain, for stacktraces
910    - prepares the local references table on the stack
911
912    The layout of the native stub stackframe should look like this:
913
914    +---------------------------+ <- SP (of parent Java function)
915    | return address            |
916    +---------------------------+
917    |                           |
918    | stackframe info structure |
919    |                           |
920    +---------------------------+
921    |                           |
922    | local references table    |
923    |                           |
924    +---------------------------+
925    |                           |
926    | arguments (if any)        |
927    |                           |
928    +---------------------------+ <- SP (native stub)
929
930 *******************************************************************************/
931
932 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
933 {
934         stackframeinfo *sfi;
935         localref_table *lrt;
936
937         /* get data structures from stack */
938
939         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
940         lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
941                                                           sizeof(localref_table));
942
943         /* add a stackframeinfo to the chain */
944
945         stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
946
947         /* add current JNI local references table to this thread */
948
949         lrt->capacity    = LOCALREFTABLE_CAPACITY;
950         lrt->used        = 0;
951         lrt->localframes = 1;
952         lrt->prev        = LOCALREFTABLE;
953
954         /* clear the references array (memset is faster the a for-loop) */
955
956         MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
957
958         LOCALREFTABLE = lrt;
959 }
960
961
962 /* codegen_finish_native_call **************************************************
963
964    Removes the stuff required for a native (JNI) function call.
965
966 *******************************************************************************/
967
968 void codegen_finish_native_call(u1 *datasp)
969 {
970         stackframeinfo  *sfi;
971         stackframeinfo **psfi;
972         localref_table  *lrt;
973         localref_table  *plrt;
974         s4               localframes;
975
976         /* get data structures from stack */
977
978         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
979         lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
980                                                           sizeof(localref_table));
981
982         /* remove current stackframeinfo from chain */
983
984         psfi = STACKFRAMEINFO;
985
986         *psfi = sfi->prev;
987
988         /* release JNI local references tables for this thread */
989
990         lrt = LOCALREFTABLE;
991
992         /* release all current local frames */
993
994         for (localframes = lrt->localframes; localframes >= 1; localframes--) {
995                 /* get previous frame */
996
997                 plrt = lrt->prev;
998
999                 /* Clear all reference entries (only for tables allocated on
1000                    the Java heap). */
1001
1002                 if (localframes > 1)
1003                         MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1004
1005                 lrt->prev = NULL;
1006
1007                 /* set new local references table */
1008
1009                 lrt = plrt;
1010         }
1011
1012         /* now store the previous local frames in the thread structure */
1013
1014         LOCALREFTABLE = lrt;
1015 }
1016
1017
1018 /* removecompilerstub **********************************************************
1019
1020    Deletes a compilerstub from memory (simply by freeing it).
1021
1022 *******************************************************************************/
1023
1024 void removecompilerstub(u1 *stub)
1025 {
1026         /* pass size 1 to keep the intern function happy */
1027
1028         CFREE((void *) stub, 1);
1029 }
1030
1031
1032 /* removenativestub ************************************************************
1033
1034    Removes a previously created native-stub from memory.
1035     
1036 *******************************************************************************/
1037
1038 void removenativestub(u1 *stub)
1039 {
1040         /* pass size 1 to keep the intern function happy */
1041
1042         CFREE((void *) stub, 1);
1043 }
1044
1045
1046 /* codegen_reg_of_var **********************************************************
1047
1048    This function determines a register, to which the result of an
1049    operation should go, when it is ultimatively intended to store the
1050    result in pseudoregister v.  If v is assigned to an actual
1051    register, this register will be returned.  Otherwise (when v is
1052    spilled) this function returns tempregnum.  If not already done,
1053    regoff and flags are set in the stack location.
1054        
1055    On ARM we have to check if a long/double variable is splitted
1056    across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1057    register of v for LOW_REG and the tempregnum for HIGH_REG in such
1058    cases.  (michi 2005/07/24)
1059
1060 *******************************************************************************/
1061
1062 s4 codegen_reg_of_var(registerdata *rd, u2 opcode, stackptr v, s4 tempregnum)
1063 {
1064         varinfo *var;
1065
1066         /* Do we have to generate a conditional move?  Yes, then always
1067            return the temporary register.  The real register is identified
1068            during the store. */
1069
1070         if (opcode & ICMD_CONDITION_MASK)
1071                 return tempregnum;
1072
1073         switch (v->varkind) {
1074         case TEMPVAR:
1075                 if (!(v->flags & INMEMORY))
1076                         return(v->regoff);
1077                 break;
1078
1079         case STACKVAR:
1080                 var = &(rd->interfaces[v->varnum][v->type]);
1081                 v->regoff = var->regoff;
1082                 if (!(var->flags & INMEMORY))
1083                         return(var->regoff);
1084                 break;
1085
1086         case LOCALVAR:
1087                 var = &(rd->locals[v->varnum][v->type]);
1088                 v->regoff = var->regoff;
1089                 if (!(var->flags & INMEMORY)) {
1090 #if defined(__ARM__) && defined(__ARMEL__)
1091                         if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
1092                                 return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
1093 #endif
1094 #if defined(__ARM__) && defined(__ARMEB__)
1095                         if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
1096                                 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
1097 #endif
1098                         return(var->regoff);
1099                 }
1100                 break;
1101
1102         case ARGVAR:
1103                 if (!(v->flags & INMEMORY)) {
1104 #if defined(__ARM__) && defined(__ARMEL__)
1105                         if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
1106                                 return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
1107 #endif
1108 #if defined(__ARM__) && defined(__ARMEB__)
1109                         if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
1110                                 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
1111 #endif
1112                         return(v->regoff);
1113                 }
1114                 break;
1115         }
1116
1117 #if defined(ENABLE_STATISTICS)
1118         if (opt_stat)
1119                 count_spills_read++;
1120 #endif
1121
1122         v->flags |= INMEMORY;
1123
1124         return tempregnum;
1125 }
1126
1127
1128 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1129 void codegen_threadcritrestart(codegendata *cd, int offset)
1130 {
1131         cd->threadcritcurrent.mcoderestart = offset;
1132 }
1133
1134
1135 void codegen_threadcritstart(codegendata *cd, int offset)
1136 {
1137         cd->threadcritcurrent.mcodebegin = offset;
1138 }
1139
1140
1141 void codegen_threadcritstop(codegendata *cd, int offset)
1142 {
1143         cd->threadcritcurrent.next = cd->threadcrit;
1144         cd->threadcritcurrent.mcodeend = offset;
1145         cd->threadcrit = DNEW(threadcritnodetemp);
1146         *(cd->threadcrit) = cd->threadcritcurrent;
1147         cd->threadcritcount++;
1148 }
1149 #endif
1150
1151
1152 /*
1153  * These are local overrides for various environment variables in Emacs.
1154  * Please do not remove this and leave it at the end of the file, where
1155  * Emacs will automagically detect them.
1156  * ---------------------------------------------------------------------
1157  * Local variables:
1158  * mode: c
1159  * indent-tabs-mode: t
1160  * c-basic-offset: 4
1161  * tab-width: 4
1162  * End:
1163  * vim:noexpandtab:sw=4:ts=4:
1164  */