* configure.ac: Added option --enable-replacement.
[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 6265 2007-01-02 20:40:57Z 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(ENABLE_REPLACEMENT)
632 #if !defined(NDEBUG)
633 void codegen_set_replacement_point_notrap(codegendata *cd, s4 type)
634 #else
635 void codegen_set_replacement_point_notrap(codegendata *cd)
636 #endif
637 {
638         assert(cd->replacementpoint);
639         assert(cd->replacementpoint->type == type);
640         assert(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP);
641
642         cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
643
644         cd->replacementpoint++;
645 }
646 #endif /* defined(ENABLE_REPLACEMENT) */
647
648
649 /* codegen_set_replacement_point ***********************************************
650
651    Record the position of a trappable replacement point.
652
653 *******************************************************************************/
654
655 #if defined(ENABLE_REPLACEMENT)
656 #if !defined(NDEBUG)
657 void codegen_set_replacement_point(codegendata *cd, s4 type)
658 #else
659 void codegen_set_replacement_point(codegendata *cd)
660 #endif
661 {
662         assert(cd->replacementpoint);
663         assert(cd->replacementpoint->type == type);
664         assert(!(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP));
665
666         cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
667
668         cd->replacementpoint++;
669
670         /* XXX assert(cd->lastmcodeptr <= cd->mcodeptr); */
671
672         cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
673 }
674 #endif /* defined(ENABLE_REPLACEMENT) */
675
676
677 /* codegen_finish **************************************************************
678
679    Finishes the code generation. A new memory, large enough for both
680    data and code, is allocated and data and code are copied together
681    to their final layout, unresolved jumps are resolved, ...
682
683 *******************************************************************************/
684
685 void codegen_finish(jitdata *jd)
686 {
687         codeinfo    *code;
688         codegendata *cd;
689         s4           mcodelen;
690 #if defined(ENABLE_INTRP)
691         s4           ncodelen;
692 #endif
693         s4           alignedmcodelen;
694         jumpref     *jr;
695         u1          *epoint;
696         s4           extralen;
697         s4           alignedlen;
698
699         /* get required compiler data */
700
701         code = jd->code;
702         cd   = jd->cd;
703
704         /* prevent compiler warning */
705
706 #if defined(ENABLE_INTRP)
707         ncodelen = 0;
708 #endif
709
710         /* calculate the code length */
711
712         mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
713
714 #if defined(ENABLE_THREADS)
715         extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
716 #else
717         extralen = 0;
718 #endif
719
720 #if defined(ENABLE_STATISTICS)
721         if (opt_stat) {
722                 count_code_len += mcodelen;
723                 count_data_len += cd->dseglen;
724         }
725 #endif
726
727         alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
728
729 #if defined(ENABLE_INTRP)
730         if (opt_intrp)
731                 ncodelen = cd->ncodeptr - cd->ncodebase;
732         else {
733                 ncodelen = 0; /* avoid compiler warning */
734         }
735 #endif
736
737         cd->dseglen = MEMORY_ALIGN(cd->dseglen, MAX_ALIGN);
738         alignedlen = alignedmcodelen + cd->dseglen;
739
740 #if defined(ENABLE_INTRP)
741         if (opt_intrp) {
742                 alignedlen += ncodelen;
743         }
744 #endif
745
746         /* allocate new memory */
747
748         code->mcodelength = mcodelen + cd->dseglen;
749         code->mcode       = CNEW(u1, alignedlen + extralen);
750
751         /* set the entrypoint of the method */
752         
753         assert(code->entrypoint == NULL);
754         code->entrypoint = epoint = (code->mcode + cd->dseglen);
755
756         /* fill the data segment (code->entrypoint must already be set!) */
757
758         dseg_finish(jd);
759
760         /* copy code to the new location */
761
762         MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
763
764 #if defined(ENABLE_INTRP)
765         /* relocate native dynamic superinstruction code (if any) */
766
767         if (opt_intrp) {
768                 cd->mcodebase = code->entrypoint;
769
770                 if (ncodelen > 0) {
771                         u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
772
773                         MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
774
775                         /* flush the instruction and data caches */
776
777                         md_cacheflush(ncodebase, ncodelen);
778
779                         /* set some cd variables for dynamic_super_rerwite */
780
781                         cd->ncodebase = ncodebase;
782
783                 } else {
784                         cd->ncodebase = NULL;
785                 }
786
787                 dynamic_super_rewrite(cd);
788         }
789 #endif
790
791         /* jump table resolving */
792
793         for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
794                 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
795                         (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
796
797         /* line number table resolving */
798         {
799                 linenumberref *lr;
800                 ptrint lrtlen = 0;
801                 ptrint target;
802
803                 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
804                         lrtlen++;
805                         target = lr->targetmpc;
806                         /* if the entry contains an mcode pointer (normal case), resolve it */
807                         /* (see doc/inlining_stacktrace.txt for details)                    */
808                         if (lr->linenumber >= -2) {
809                             target += (ptrint) epoint;
810                         }
811                         *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) = 
812                                 (functionptr) target;
813                 }
814                 
815                 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
816                         (functionptr) ((ptrint) epoint + cd->linenumbertab);
817
818                 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
819         }
820
821 #if defined(ENABLE_REPLACEMENT)
822         /* replacement point resolving */
823         {
824                 int i;
825                 rplpoint *rp;
826
827                 code->replacementstubs += (ptrint) epoint;
828
829                 rp = code->rplpoints;
830                 for (i=0; i<code->rplpointcount; ++i, ++rp) {
831                         rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
832                 }
833         }
834 #endif /* defined(ENABLE_REPLACEMENT) */
835
836         /* add method into methodtree to find the entrypoint */
837
838         codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
839
840 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
841         /* resolve data segment references */
842
843         dseg_resolve_datareferences(jd);
844 #endif
845
846 #if defined(ENABLE_THREADS)
847         {
848                 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
849                 s4 i;
850                 codegen_critical_section_t *nt = cd->threadcrit;
851
852                 for (i = 0; i < cd->threadcritcount; i++) {
853                         n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
854                         n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
855                         n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
856                         critical_register_critical_section(n);
857                         n++;
858                         nt = nt->next;
859                 }
860         }
861 #endif
862
863         /* flush the instruction and data caches */
864
865         md_cacheflush(code->mcode, code->mcodelength);
866 }
867
868
869 /* codegen_createnativestub ****************************************************
870
871    Wrapper for createnativestub.
872
873    Returns:
874        the codeinfo representing the stub code.
875
876 *******************************************************************************/
877
878 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
879 {
880         jitdata     *jd;
881         codeinfo    *code;
882         s4           dumpsize;
883         methoddesc  *md;
884         methoddesc  *nmd;       
885         s4           nativeparams;
886
887         /* mark dump memory */
888
889         dumpsize = dump_size();
890
891         jd = DNEW(jitdata);
892
893         jd->m     = m;
894         jd->cd    = DNEW(codegendata);
895         jd->rd    = DNEW(registerdata);
896         jd->flags = 0;
897
898         /* Allocate codeinfo memory from the heap as we need to keep them. */
899
900         jd->code  = code_codeinfo_new(m); /* XXX check allocation */
901
902         /* get required compiler data */
903
904         code = jd->code;
905
906         /* set the flags for the current JIT run */
907
908 #if defined(ENABLE_PROFILING)
909         if (opt_prof)
910                 jd->flags |= JITDATA_FLAG_INSTRUMENT;
911 #endif
912
913         if (opt_verbosecall)
914                 jd->flags |= JITDATA_FLAG_VERBOSECALL;
915
916         /* setup code generation stuff */
917
918 #if defined(ENABLE_JIT)
919 # if defined(ENABLE_INTRP)
920         if (!opt_intrp)
921 # endif
922                 reg_setup(jd);
923 #endif
924
925         codegen_setup(jd);
926
927         /* create new method descriptor with additional native parameters */
928
929         md = m->parseddesc;
930         nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
931         
932         nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
933                                                            md->paramcount * sizeof(typedesc) +
934                                                            nativeparams * sizeof(typedesc));
935
936         nmd->paramcount = md->paramcount + nativeparams;
937
938         nmd->params = DMNEW(paramdesc, nmd->paramcount);
939
940         nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer            */
941
942         if (m->flags & ACC_STATIC)
943                 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer              */
944
945         MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
946                   md->paramcount);
947
948 #if defined(ENABLE_JIT)
949 # if defined(ENABLE_INTRP)
950         if (!opt_intrp)
951 # endif
952                 md_param_alloc(nmd);
953 #endif
954
955         /* generate the code */
956
957 #if defined(ENABLE_JIT)
958 # if defined(ENABLE_INTRP)
959         if (opt_intrp)
960                 code->entrypoint = intrp_createnativestub(f, jd, nmd);
961         else
962 # endif
963                 code->entrypoint = createnativestub(f, jd, nmd);
964 #else
965         code->entrypoint = intrp_createnativestub(f, jd, nmd);
966 #endif
967
968 #if defined(ENABLE_STATISTICS)
969         if (opt_stat)
970                 count_nstub_len += code->mcodelength;
971 #endif
972
973 #if !defined(NDEBUG)
974         /* disassemble native stub */
975
976         if (opt_shownativestub) {
977 #if defined(ENABLE_DISASSEMBLER)
978                 codegen_disassemble_nativestub(m,
979                                                                            (u1 *) (ptrint) code->entrypoint,
980                                                                            (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
981 #endif
982
983                 /* show data segment */
984
985                 if (opt_showddatasegment)
986                         dseg_display(jd);
987         }
988 #endif /* !defined(NDEBUG) */
989
990         /* release memory */
991
992         dump_release(dumpsize);
993
994         /* return native stub code */
995
996         return code;
997 }
998
999
1000 /* codegen_disassemble_nativestub **********************************************
1001
1002    Disassembles the generated native stub.
1003
1004 *******************************************************************************/
1005
1006 #if defined(ENABLE_DISASSEMBLER)
1007 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
1008 {
1009         printf("Native stub: ");
1010         utf_fprint_printable_ascii_classname(stdout, m->class->name);
1011         printf(".");
1012         utf_fprint_printable_ascii(stdout, m->name);
1013         utf_fprint_printable_ascii(stdout, m->descriptor);
1014         printf("\n\nLength: %d\n\n", (s4) (end - start));
1015
1016         DISASSEMBLE(start, end);
1017 }
1018 #endif
1019
1020
1021 /* codegen_start_native_call ***************************************************
1022
1023    Prepares the stuff required for a native (JNI) function call:
1024
1025    - adds a stackframe info structure to the chain, for stacktraces
1026    - prepares the local references table on the stack
1027
1028    The layout of the native stub stackframe should look like this:
1029
1030    +---------------------------+ <- SP (of parent Java function)
1031    | return address            |
1032    +---------------------------+
1033    |                           |
1034    | stackframe info structure |
1035    |                           |
1036    +---------------------------+
1037    |                           |
1038    | local references table    |
1039    |                           |
1040    +---------------------------+
1041    |                           |
1042    | arguments (if any)        |
1043    |                           |
1044    +---------------------------+ <- SP (native stub)
1045
1046 *******************************************************************************/
1047
1048 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
1049 {
1050         stackframeinfo *sfi;
1051         localref_table *lrt;
1052
1053         /* get data structures from stack */
1054
1055         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1056         lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
1057                                                           sizeof(localref_table));
1058
1059         /* add a stackframeinfo to the chain */
1060
1061         stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1062
1063 #if defined(ENABLE_JAVASE)
1064         /* add current JNI local references table to this thread */
1065
1066         lrt->capacity    = LOCALREFTABLE_CAPACITY;
1067         lrt->used        = 0;
1068         lrt->localframes = 1;
1069         lrt->prev        = LOCALREFTABLE;
1070
1071         /* clear the references array (memset is faster the a for-loop) */
1072
1073         MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1074
1075         LOCALREFTABLE = lrt;
1076 #endif
1077 }
1078
1079
1080 /* codegen_finish_native_call **************************************************
1081
1082    Removes the stuff required for a native (JNI) function call.
1083    Additionally it checks for an exceptions and in case, get the
1084    exception object and clear the pointer.
1085
1086 *******************************************************************************/
1087
1088 java_objectheader *codegen_finish_native_call(u1 *datasp)
1089 {
1090         stackframeinfo     *sfi;
1091         stackframeinfo    **psfi;
1092         localref_table     *lrt;
1093         localref_table     *plrt;
1094         s4                  localframes;
1095         java_objectheader  *e;
1096
1097         /* get data structures from stack */
1098
1099         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1100         lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
1101                                                           sizeof(localref_table));
1102
1103         /* remove current stackframeinfo from chain */
1104
1105         psfi = STACKFRAMEINFO;
1106
1107         *psfi = sfi->prev;
1108
1109 #if defined(ENABLE_JAVASE)
1110         /* release JNI local references tables for this thread */
1111
1112         lrt = LOCALREFTABLE;
1113
1114         /* release all current local frames */
1115
1116         for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1117                 /* get previous frame */
1118
1119                 plrt = lrt->prev;
1120
1121                 /* Clear all reference entries (only for tables allocated on
1122                    the Java heap). */
1123
1124                 if (localframes > 1)
1125                         MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1126
1127                 lrt->prev = NULL;
1128
1129                 /* set new local references table */
1130
1131                 lrt = plrt;
1132         }
1133
1134         /* now store the previous local frames in the thread structure */
1135
1136         LOCALREFTABLE = lrt;
1137 #endif
1138
1139         /* get the exception and return it */
1140
1141         e = exceptions_get_and_clear_exception();
1142
1143         return e;
1144 }
1145
1146
1147 /* removecompilerstub **********************************************************
1148
1149    Deletes a compilerstub from memory (simply by freeing it).
1150
1151 *******************************************************************************/
1152
1153 void removecompilerstub(u1 *stub)
1154 {
1155         /* pass size 1 to keep the intern function happy */
1156
1157         CFREE((void *) stub, 1);
1158 }
1159
1160
1161 /* removenativestub ************************************************************
1162
1163    Removes a previously created native-stub from memory.
1164     
1165 *******************************************************************************/
1166
1167 void removenativestub(u1 *stub)
1168 {
1169         /* pass size 1 to keep the intern function happy */
1170
1171         CFREE((void *) stub, 1);
1172 }
1173
1174
1175 /* codegen_reg_of_var **********************************************************
1176
1177    This function determines a register, to which the result of an
1178    operation should go, when it is ultimatively intended to store the
1179    result in pseudoregister v.  If v is assigned to an actual
1180    register, this register will be returned.  Otherwise (when v is
1181    spilled) this function returns tempregnum.  If not already done,
1182    regoff and flags are set in the stack location.
1183        
1184    On ARM we have to check if a long/double variable is splitted
1185    across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1186    register of v for LOW_REG and the tempregnum for HIGH_REG in such
1187    cases.  (michi 2005/07/24)
1188
1189 *******************************************************************************/
1190
1191 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
1192 {
1193
1194 #if 0
1195         /* Do we have to generate a conditional move?  Yes, then always
1196            return the temporary register.  The real register is identified
1197            during the store. */
1198
1199         if (opcode & ICMD_CONDITION_MASK)
1200                 return tempregnum;
1201 #endif
1202
1203         if (!(v->flags & INMEMORY)) {
1204 #if defined(__ARM__) && defined(__ARMEL__)
1205                 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
1206                         return PACK_REGS(GET_LOW_REG(v->vv.regoff),
1207                                                          GET_HIGH_REG(tempregnum));
1208 #endif
1209 #if defined(__ARM__) && defined(__ARMEB__)
1210                 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
1211                         return PACK_REGS(GET_LOW_REG(tempregnum),
1212                                                          GET_HIGH_REG(v->vv.regoff));
1213 #endif
1214                 return v->vv.regoff;
1215         }
1216
1217 #if defined(ENABLE_STATISTICS)
1218         if (opt_stat)
1219                 count_spills_read++;
1220 #endif
1221
1222         return tempregnum;
1223 }
1224
1225 /* codegen_reg_of_dst **********************************************************
1226
1227    This function determines a register, to which the result of an
1228    operation should go, when it is ultimatively intended to store the
1229    result in iptr->dst.var.  If dst.var is assigned to an actual
1230    register, this register will be returned.  Otherwise (when it is
1231    spilled) this function returns tempregnum.  If not already done,
1232    regoff and flags are set in the stack location.
1233        
1234    On ARM we have to check if a long/double variable is splitted
1235    across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1236    register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
1237    cases.  (michi 2005/07/24)
1238
1239 *******************************************************************************/
1240
1241 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1242 {
1243         return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
1244 }
1245
1246
1247 #if defined(ENABLE_THREADS)
1248 void codegen_threadcritrestart(codegendata *cd, int offset)
1249 {
1250         cd->threadcritcurrent.mcoderestart = offset;
1251 }
1252
1253
1254 void codegen_threadcritstart(codegendata *cd, int offset)
1255 {
1256         cd->threadcritcurrent.mcodebegin = offset;
1257 }
1258
1259
1260 void codegen_threadcritstop(codegendata *cd, int offset)
1261 {
1262         cd->threadcritcurrent.next = cd->threadcrit;
1263         cd->threadcritcurrent.mcodeend = offset;
1264         cd->threadcrit = DNEW(codegen_critical_section_t);
1265         *(cd->threadcrit) = cd->threadcritcurrent;
1266         cd->threadcritcount++;
1267 }
1268 #endif
1269
1270
1271 /*
1272  * These are local overrides for various environment variables in Emacs.
1273  * Please do not remove this and leave it at the end of the file, where
1274  * Emacs will automagically detect them.
1275  * ---------------------------------------------------------------------
1276  * Local variables:
1277  * mode: c
1278  * indent-tabs-mode: t
1279  * c-basic-offset: 4
1280  * tab-width: 4
1281  * End:
1282  * vim:noexpandtab:sw=4:ts=4:
1283  */