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