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