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