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