* codegen_finish: Moved data segment reference resolving into
[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 4199 2006-01-13 15:29:21Z 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(ENABLE_JIT)
63 /* this is required for gen_resolvebranch and 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(ENABLE_JIT) && (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                         /* XXX cacheflush((void *)ncodebase, ncodelen); */
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
742 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
743         /* resolve data segment references */
744
745         dseg_resolve_datareferences(cd, m);
746 #endif
747
748
749 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
750         {
751                 threadcritnode *n = (threadcritnode *) ((ptrint) m->mcode + alignedlen);
752                 s4 i;
753                 threadcritnodetemp *nt = cd->threadcrit;
754
755                 for (i = 0; i < cd->threadcritcount; i++) {
756                         n->mcodebegin = (u1 *) (ptrint) m->mcode + nt->mcodebegin;
757                         n->mcodeend = (u1 *) (ptrint) m->mcode + nt->mcodeend;
758                         n->mcoderestart = (u1 *) (ptrint) m->mcode + nt->mcoderestart;
759                         thread_registercritical(n);
760                         n++;
761                         nt = nt->next;
762                 }
763         }
764 #endif
765 }
766
767
768 /* codegen_createnativestub ****************************************************
769
770    Wrapper for createnativestub.
771
772 *******************************************************************************/
773
774 u1 *codegen_createnativestub(functionptr f, methodinfo *m)
775 {
776         codegendata        *cd;
777         registerdata       *rd;
778         t_inlining_globals *id;
779         s4                  dumpsize;
780         methoddesc         *md;
781         methoddesc         *nmd;        
782         s4                  nativeparams;
783
784         /* mark dump memory */
785
786         dumpsize = dump_size();
787
788         cd = DNEW(codegendata);
789         rd = DNEW(registerdata);
790         id = DNEW(t_inlining_globals);
791
792         /* setup code generation stuff */
793
794         inlining_setup(m, id);
795
796 #if defined(ENABLE_JIT)
797 # if defined(ENABLE_INTRP)
798         if (!opt_intrp)
799 # endif
800                 reg_setup(m, rd, id);
801 #endif
802
803         codegen_setup(m, cd, id);
804                                                 
805         /* create new method descriptor with additional native parameters */
806
807         md = m->parseddesc;
808         nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
809         
810         nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
811                                                            md->paramcount * sizeof(typedesc) +
812                                                            nativeparams * sizeof(typedesc));
813
814         nmd->paramcount = md->paramcount + nativeparams;
815
816         nmd->params = DMNEW(paramdesc, nmd->paramcount);
817
818         nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer            */
819
820         if (m->flags & ACC_STATIC)
821                 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer              */
822
823         MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
824                   md->paramcount);
825
826 #if defined(ENABLE_JIT)
827 # if defined(ENABLE_INTRP)
828         if (!opt_intrp)
829 # endif
830                 md_param_alloc(nmd);
831 #endif
832
833         /* generate the code */
834
835 #if defined(ENABLE_JIT)
836 # if defined(ENABLE_INTRP)
837         if (opt_intrp)
838                 m->entrypoint = intrp_createnativestub(f, m, cd, rd, nmd);
839         else
840 # endif
841                 m->entrypoint = createnativestub(f, m, cd, rd, nmd);
842 #else
843         m->entrypoint = intrp_createnativestub(f, m, cd, rd, nmd);
844 #endif
845
846 #if defined(ENABLE_STATISTICS)
847         if (opt_stat)
848                 count_nstub_len += m->mcodelength;
849 #endif
850
851         /* disassemble native stub */
852
853         if (opt_shownativestub) {
854                 codegen_disassemble_nativestub(m,
855                                                                            (u1 *) (ptrint) m->entrypoint,
856                                                                            (u1 *) (ptrint) m->entrypoint + (m->mcodelength - cd->dseglen));
857
858                 /* show data segment */
859
860                 if (opt_showddatasegment)
861                         dseg_display(m, cd);
862         }
863
864         /* release memory */
865
866         dump_release(dumpsize);
867
868         /* return native stub entry point */
869
870         return m->entrypoint;
871 }
872
873
874 /* codegen_disassemble_nativestub **********************************************
875
876    Disassembles the generated native stub.
877
878 *******************************************************************************/
879
880 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
881 {
882         printf("Native stub: ");
883         utf_fprint_classname(stdout, m->class->name);
884         printf(".");
885         utf_fprint(stdout, m->name);
886         utf_fprint(stdout, m->descriptor);
887         printf("\n\nLength: %d\n\n", (s4) (end - start));
888
889         DISASSEMBLE(start, end);
890 }
891
892
893 /* codegen_start_native_call ***************************************************
894
895    Prepares the stuff required for a native (JNI) function call:
896
897    - adds a stackframe info structure to the chain, for stacktraces
898    - prepares the local references table on the stack
899
900    The layout of the native stub stackframe should look like this:
901
902    +---------------------------+ <- SP (of parent Java function)
903    | return address            |
904    +---------------------------+
905    |                           |
906    | stackframe info structure |
907    |                           |
908    +---------------------------+
909    |                           |
910    | local references table    |
911    |                           |
912    +---------------------------+
913    |                           |
914    | arguments (if any)        |
915    |                           |
916    +---------------------------+ <- SP (native stub)
917
918 *******************************************************************************/
919
920 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
921 {
922         stackframeinfo *sfi;
923         localref_table *lrt;
924
925         /* get data structures from stack */
926
927         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
928         lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
929                                                           sizeof(localref_table));
930
931         /* add a stackframeinfo to the chain */
932
933         stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
934
935         /* add current JNI local references table to this thread */
936
937         lrt->capacity    = LOCALREFTABLE_CAPACITY;
938         lrt->used        = 0;
939         lrt->localframes = 1;
940         lrt->prev        = LOCALREFTABLE;
941
942         /* clear the references array (memset is faster the a for-loop) */
943
944         MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
945
946         LOCALREFTABLE = lrt;
947 }
948
949
950 /* codegen_finish_native_call **************************************************
951
952    Removes the stuff required for a native (JNI) function call.
953
954 *******************************************************************************/
955
956 void codegen_finish_native_call(u1 *datasp)
957 {
958         stackframeinfo  *sfi;
959         stackframeinfo **psfi;
960         localref_table  *lrt;
961         s4               localframes;
962
963         /* get data structures from stack */
964
965         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
966         lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
967                                                           sizeof(localref_table));
968
969         /* remove current stackframeinfo from chain */
970
971         psfi = STACKFRAMEINFO;
972
973         *psfi = sfi->prev;
974
975         /* release JNI local references tables for this thread */
976
977         lrt = LOCALREFTABLE;
978
979         /* got through all current local frames */
980
981         for (localframes = lrt->localframes; localframes >= 1; localframes--) {
982                 lrt = lrt->prev;
983         }
984
985         /* now store the previous local frames in the thread structure */
986
987         LOCALREFTABLE = lrt;
988 }
989
990
991 /* removecompilerstub **********************************************************
992
993    Deletes a compilerstub from memory (simply by freeing it).
994
995 *******************************************************************************/
996
997 void removecompilerstub(u1 *stub)
998 {
999         /* pass size 1 to keep the intern function happy */
1000
1001         CFREE((void *) stub, 1);
1002 }
1003
1004
1005 /* removenativestub ************************************************************
1006
1007    Removes a previously created native-stub from memory.
1008     
1009 *******************************************************************************/
1010
1011 void removenativestub(u1 *stub)
1012 {
1013         /* pass size 1 to keep the intern function happy */
1014
1015         CFREE((void *) stub, 1);
1016 }
1017
1018
1019 /* reg_of_var ******************************************************************
1020
1021    This function determines a register, to which the result of an
1022    operation should go, when it is ultimatively intended to store the
1023    result in pseudoregister v.  If v is assigned to an actual
1024    register, this register will be returned.  Otherwise (when v is
1025    spilled) this function returns tempregnum.  If not already done,
1026    regoff and flags are set in the stack location.
1027        
1028    On ARM we have to check if a long/double variable is splitted
1029    across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1030    register of v for LOW_REG and the tempregnum for HIGH_REG in such
1031    cases.  (michi 2005/07/24)
1032
1033 *******************************************************************************/
1034
1035 s4 reg_of_var(registerdata *rd, stackptr v, s4 tempregnum)
1036 {
1037         varinfo *var;
1038
1039         switch (v->varkind) {
1040         case TEMPVAR:
1041                 if (!(v->flags & INMEMORY))
1042                         return(v->regoff);
1043                 break;
1044
1045         case STACKVAR:
1046                 var = &(rd->interfaces[v->varnum][v->type]);
1047                 v->regoff = var->regoff;
1048                 if (!(var->flags & INMEMORY))
1049                         return(var->regoff);
1050                 break;
1051
1052         case LOCALVAR:
1053                 var = &(rd->locals[v->varnum][v->type]);
1054                 v->regoff = var->regoff;
1055                 if (!(var->flags & INMEMORY)) {
1056 #if defined(__ARM__) && defined(__ARMEL__)
1057                         if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
1058                                 return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
1059 #endif
1060 #if defined(__ARM__) && defined(__ARMEB__)
1061                         if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
1062                                 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
1063 #endif
1064                         return(var->regoff);
1065                 }
1066                 break;
1067
1068         case ARGVAR:
1069                 if (!(v->flags & INMEMORY)) {
1070 #if defined(__ARM__) && defined(__ARMEL__)
1071                         if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
1072                                 return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
1073 #endif
1074 #if defined(__ARM__) && defined(__ARMEB__)
1075                         if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
1076                                 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
1077 #endif
1078                         return(v->regoff);
1079                 }
1080                 break;
1081         }
1082
1083 #if defined(ENABLE_STATISTICS)
1084         if (opt_stat)
1085                 count_spills_read++;
1086 #endif
1087
1088         v->flags |= INMEMORY;
1089
1090         return tempregnum;
1091 }
1092
1093
1094 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1095 void codegen_threadcritrestart(codegendata *cd, int offset)
1096 {
1097         cd->threadcritcurrent.mcoderestart = offset;
1098 }
1099
1100
1101 void codegen_threadcritstart(codegendata *cd, int offset)
1102 {
1103         cd->threadcritcurrent.mcodebegin = offset;
1104 }
1105
1106
1107 void codegen_threadcritstop(codegendata *cd, int offset)
1108 {
1109         cd->threadcritcurrent.next = cd->threadcrit;
1110         cd->threadcritcurrent.mcodeend = offset;
1111         cd->threadcrit = DNEW(threadcritnodetemp);
1112         *(cd->threadcrit) = cd->threadcritcurrent;
1113         cd->threadcritcount++;
1114 }
1115 #endif
1116
1117
1118 /*
1119  * These are local overrides for various environment variables in Emacs.
1120  * Please do not remove this and leave it at the end of the file, where
1121  * Emacs will automagically detect them.
1122  * ---------------------------------------------------------------------
1123  * Local variables:
1124  * mode: c
1125  * indent-tabs-mode: t
1126  * c-basic-offset: 4
1127  * tab-width: 4
1128  * End:
1129  */