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