* src/vm/jit/powerpc/codegen.c (codegen): Use codegen_add_branch_ref,
[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 5943 2006-11-09 15:27:03Z 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(__MIPS__) || defined(__POWERPC__))
482         /* Generate NOPs for opt_shownops. */
483
484         if (opt_shownops)
485                 PATCHER_NOPS;
486 #endif
487
488 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
489         /* On some architectures the patcher stub call instruction might
490            be longer than the actual instruction generated.  On this
491            architectures we store the last patcher call position and after
492            the basic block code generation is completed, we check the
493            range and maybe generate some nop's. */
494
495         cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
496 #endif
497 }
498
499
500 /* methodtree_comparator *******************************************************
501
502    Comparator function used for the AVL tree of methods.
503
504 *******************************************************************************/
505
506 static s4 methodtree_comparator(const void *pc, const void *element)
507 {
508         methodtree_element *mte;
509         methodtree_element *mtepc;
510
511         mte = (methodtree_element *) element;
512         mtepc = (methodtree_element *) pc;
513
514         /* compare both startpc and endpc of pc, even if they have the same value,
515            otherwise the avl_probe sometimes thinks the element is already in the
516            tree */
517
518         if ((long) mte->startpc <= (long) mtepc->startpc &&
519                 (long) mtepc->startpc <= (long) mte->endpc &&
520                 (long) mte->startpc <= (long) mtepc->endpc &&
521                 (long) mtepc->endpc <= (long) mte->endpc) {
522                 return 0;
523
524         } else if ((long) mtepc->startpc < (long) mte->startpc) {
525                 return -1;
526
527         } else {
528                 return 1;
529         }
530 }
531
532
533 /* codegen_insertmethod ********************************************************
534
535    Insert the machine code range of a method into the AVL tree of methods.
536
537 *******************************************************************************/
538
539 void codegen_insertmethod(u1 *startpc, u1 *endpc)
540 {
541         methodtree_element *mte;
542
543         /* allocate new method entry */
544
545         mte = NEW(methodtree_element);
546
547         mte->startpc = startpc;
548         mte->endpc   = endpc;
549
550         /* this function does not return an error, but asserts for
551            duplicate entries */
552
553         avl_insert(methodtree, mte);
554 }
555
556
557 /* codegen_get_pv_from_pc ******************************************************
558
559    Find the PV for the given PC by searching in the AVL tree of
560    methods.
561
562 *******************************************************************************/
563
564 u1 *codegen_get_pv_from_pc(u1 *pc)
565 {
566         methodtree_element  mtepc;
567         methodtree_element *mte;
568
569         /* allocation of the search structure on the stack is much faster */
570
571         mtepc.startpc = pc;
572         mtepc.endpc   = pc;
573
574         mte = avl_find(methodtree, &mtepc);
575
576         if (mte == NULL) {
577                 /* No method was found.  Let's dump a stacktrace. */
578
579                 log_println("We received a SIGSEGV and tried to handle it, but we were");
580                 log_println("unable to find a Java method at:");
581                 log_println("");
582 #if SIZEOF_VOID_P == 8
583                 log_println("PC=0x%016lx", pc);
584 #else
585                 log_println("PC=0x%08x", pc);
586 #endif
587                 log_println("");
588                 log_println("Dumping the current stacktrace:");
589
590                 stacktrace_dump_trace(THREADOBJECT);
591
592                 vm_abort("Exiting...");
593         }
594
595         return mte->startpc;
596 }
597
598
599 /* codegen_get_pv_from_pc_nocheck **********************************************
600
601    Find the PV for the given PC by searching in the AVL tree of
602    methods.  This method does not check the return value and is used
603    by the profiler.
604
605 *******************************************************************************/
606
607 u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
608 {
609         methodtree_element  mtepc;
610         methodtree_element *mte;
611
612         /* allocation of the search structure on the stack is much faster */
613
614         mtepc.startpc = pc;
615         mtepc.endpc   = pc;
616
617         mte = avl_find(methodtree, &mtepc);
618
619         if (mte == NULL)
620                 return NULL;
621         else
622                 return mte->startpc;
623 }
624
625
626 /* codegen_finish **************************************************************
627
628    Finishes the code generation. A new memory, large enough for both
629    data and code, is allocated and data and code are copied together
630    to their final layout, unresolved jumps are resolved, ...
631
632 *******************************************************************************/
633
634 void codegen_finish(jitdata *jd)
635 {
636         codeinfo    *code;
637         codegendata *cd;
638         s4           mcodelen;
639 #if defined(ENABLE_INTRP)
640         s4           ncodelen;
641 #endif
642         s4           alignedmcodelen;
643         jumpref     *jr;
644         u1          *epoint;
645         s4           extralen;
646         s4           alignedlen;
647
648         /* get required compiler data */
649
650         code = jd->code;
651         cd   = jd->cd;
652
653         /* prevent compiler warning */
654
655 #if defined(ENABLE_INTRP)
656         ncodelen = 0;
657 #endif
658
659         /* calculate the code length */
660
661         mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
662
663 #if defined(ENABLE_THREADS)
664         extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
665 #else
666         extralen = 0;
667 #endif
668
669 #if defined(ENABLE_STATISTICS)
670         if (opt_stat) {
671                 count_code_len += mcodelen;
672                 count_data_len += cd->dseglen;
673         }
674 #endif
675
676         alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
677
678 #if defined(ENABLE_INTRP)
679         if (opt_intrp)
680                 ncodelen = cd->ncodeptr - cd->ncodebase;
681         else {
682                 ncodelen = 0; /* avoid compiler warning */
683         }
684 #endif
685
686         cd->dseglen = MEMORY_ALIGN(cd->dseglen, MAX_ALIGN);
687         alignedlen = alignedmcodelen + cd->dseglen;
688
689 #if defined(ENABLE_INTRP)
690         if (opt_intrp) {
691                 alignedlen += ncodelen;
692         }
693 #endif
694
695         /* allocate new memory */
696
697         code->mcodelength = mcodelen + cd->dseglen;
698         code->mcode       = CNEW(u1, alignedlen + extralen);
699
700         /* set the entrypoint of the method */
701         
702         assert(code->entrypoint == NULL);
703         code->entrypoint = epoint = (code->mcode + cd->dseglen);
704
705         /* fill the data segment (code->entrypoint must already be set!) */
706
707         dseg_finish(jd);
708
709         /* copy code to the new location */
710
711         MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
712
713 #if defined(ENABLE_INTRP)
714         /* relocate native dynamic superinstruction code (if any) */
715
716         if (opt_intrp) {
717                 cd->mcodebase = code->entrypoint;
718
719                 if (ncodelen > 0) {
720                         u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
721
722                         MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
723
724                         /* flush the instruction and data caches */
725
726                         md_cacheflush(ncodebase, ncodelen);
727
728                         /* set some cd variables for dynamic_super_rerwite */
729
730                         cd->ncodebase = ncodebase;
731
732                 } else {
733                         cd->ncodebase = NULL;
734                 }
735
736                 dynamic_super_rewrite(cd);
737         }
738 #endif
739
740         /* jump table resolving */
741
742         for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
743                 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
744                         (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
745
746         /* line number table resolving */
747         {
748                 linenumberref *lr;
749                 ptrint lrtlen = 0;
750                 ptrint target;
751
752                 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
753                         lrtlen++;
754                         target = lr->targetmpc;
755                         /* if the entry contains an mcode pointer (normal case), resolve it */
756                         /* (see doc/inlining_stacktrace.txt for details)                    */
757                         if (lr->linenumber >= -2) {
758                             target += (ptrint) epoint;
759                         }
760                         *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) = 
761                                 (functionptr) target;
762                 }
763                 
764                 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
765                         (functionptr) ((ptrint) epoint + cd->linenumbertab);
766
767                 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
768         }
769
770         /* replacement point resolving */
771         {
772                 int i;
773                 rplpoint *rp;
774
775                 rp = code->rplpoints;
776                 for (i=0; i<code->rplpointcount; ++i, ++rp) {
777                         rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
778                         rp->outcode = (u1*) ((ptrint) epoint + (ptrint) rp->outcode);
779                 }
780         }
781
782         /* add method into methodtree to find the entrypoint */
783
784         codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
785
786 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
787         /* resolve data segment references */
788
789         dseg_resolve_datareferences(jd);
790 #endif
791
792 #if defined(ENABLE_THREADS)
793         {
794                 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
795                 s4 i;
796                 codegen_critical_section_t *nt = cd->threadcrit;
797
798                 for (i = 0; i < cd->threadcritcount; i++) {
799                         n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
800                         n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
801                         n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
802                         critical_register_critical_section(n);
803                         n++;
804                         nt = nt->next;
805                 }
806         }
807 #endif
808
809         /* flush the instruction and data caches */
810
811         md_cacheflush(code->mcode, code->mcodelength);
812 }
813
814
815 /* codegen_createnativestub ****************************************************
816
817    Wrapper for createnativestub.
818
819    Returns:
820        the codeinfo representing the stub code.
821
822 *******************************************************************************/
823
824 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
825 {
826         jitdata     *jd;
827         codeinfo    *code;
828         s4           dumpsize;
829         methoddesc  *md;
830         methoddesc  *nmd;       
831         s4           nativeparams;
832
833         /* mark dump memory */
834
835         dumpsize = dump_size();
836
837         jd = DNEW(jitdata);
838
839         jd->m     = m;
840         jd->cd    = DNEW(codegendata);
841         jd->rd    = DNEW(registerdata);
842         jd->flags = 0;
843
844         /* Allocate codeinfo memory from the heap as we need to keep them. */
845
846         jd->code  = code_codeinfo_new(m); /* XXX check allocation */
847
848         /* get required compiler data */
849
850         code = jd->code;
851
852         /* set the flags for the current JIT run */
853
854 #if defined(ENABLE_PROFILING)
855         if (opt_prof)
856                 jd->flags |= JITDATA_FLAG_INSTRUMENT;
857 #endif
858
859         if (opt_verbosecall)
860                 jd->flags |= JITDATA_FLAG_VERBOSECALL;
861
862         /* setup code generation stuff */
863
864 #if defined(ENABLE_JIT)
865 # if defined(ENABLE_INTRP)
866         if (!opt_intrp)
867 # endif
868                 reg_setup(jd);
869 #endif
870
871         codegen_setup(jd);
872
873         /* create new method descriptor with additional native parameters */
874
875         md = m->parseddesc;
876         nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
877         
878         nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
879                                                            md->paramcount * sizeof(typedesc) +
880                                                            nativeparams * sizeof(typedesc));
881
882         nmd->paramcount = md->paramcount + nativeparams;
883
884         nmd->params = DMNEW(paramdesc, nmd->paramcount);
885
886         nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer            */
887
888         if (m->flags & ACC_STATIC)
889                 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer              */
890
891         MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
892                   md->paramcount);
893
894 #if defined(ENABLE_JIT)
895 # if defined(ENABLE_INTRP)
896         if (!opt_intrp)
897 # endif
898                 md_param_alloc(nmd);
899 #endif
900
901         /* generate the code */
902
903 #if defined(ENABLE_JIT)
904 # if defined(ENABLE_INTRP)
905         if (opt_intrp)
906                 code->entrypoint = intrp_createnativestub(f, jd, nmd);
907         else
908 # endif
909                 code->entrypoint = createnativestub(f, jd, nmd);
910 #else
911         code->entrypoint = intrp_createnativestub(f, jd, nmd);
912 #endif
913
914 #if defined(ENABLE_STATISTICS)
915         if (opt_stat)
916                 count_nstub_len += code->mcodelength;
917 #endif
918
919 #if !defined(NDEBUG)
920         /* disassemble native stub */
921
922         if (opt_shownativestub) {
923 #if defined(ENABLE_DISASSEMBLER)
924                 codegen_disassemble_nativestub(m,
925                                                                            (u1 *) (ptrint) code->entrypoint,
926                                                                            (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
927 #endif
928
929                 /* show data segment */
930
931                 if (opt_showddatasegment)
932                         dseg_display(jd);
933         }
934 #endif /* !defined(NDEBUG) */
935
936         /* release memory */
937
938         dump_release(dumpsize);
939
940         /* return native stub code */
941
942         return code;
943 }
944
945
946 /* codegen_disassemble_nativestub **********************************************
947
948    Disassembles the generated native stub.
949
950 *******************************************************************************/
951
952 #if defined(ENABLE_DISASSEMBLER)
953 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
954 {
955         printf("Native stub: ");
956         utf_fprint_printable_ascii_classname(stdout, m->class->name);
957         printf(".");
958         utf_fprint_printable_ascii(stdout, m->name);
959         utf_fprint_printable_ascii(stdout, m->descriptor);
960         printf("\n\nLength: %d\n\n", (s4) (end - start));
961
962         DISASSEMBLE(start, end);
963 }
964 #endif
965
966
967 /* codegen_start_native_call ***************************************************
968
969    Prepares the stuff required for a native (JNI) function call:
970
971    - adds a stackframe info structure to the chain, for stacktraces
972    - prepares the local references table on the stack
973
974    The layout of the native stub stackframe should look like this:
975
976    +---------------------------+ <- SP (of parent Java function)
977    | return address            |
978    +---------------------------+
979    |                           |
980    | stackframe info structure |
981    |                           |
982    +---------------------------+
983    |                           |
984    | local references table    |
985    |                           |
986    +---------------------------+
987    |                           |
988    | arguments (if any)        |
989    |                           |
990    +---------------------------+ <- SP (native stub)
991
992 *******************************************************************************/
993
994 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
995 {
996         stackframeinfo *sfi;
997         localref_table *lrt;
998
999         /* get data structures from stack */
1000
1001         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1002         lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
1003                                                           sizeof(localref_table));
1004
1005         /* add a stackframeinfo to the chain */
1006
1007         stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1008
1009         /* add current JNI local references table to this thread */
1010
1011         lrt->capacity    = LOCALREFTABLE_CAPACITY;
1012         lrt->used        = 0;
1013         lrt->localframes = 1;
1014         lrt->prev        = LOCALREFTABLE;
1015
1016         /* clear the references array (memset is faster the a for-loop) */
1017
1018         MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1019
1020         LOCALREFTABLE = lrt;
1021 }
1022
1023
1024 /* codegen_finish_native_call **************************************************
1025
1026    Removes the stuff required for a native (JNI) function call.
1027    Additionally it checks for an exceptions and in case, get the
1028    exception object and clear the pointer.
1029
1030 *******************************************************************************/
1031
1032 java_objectheader *codegen_finish_native_call(u1 *datasp)
1033 {
1034         stackframeinfo     *sfi;
1035         stackframeinfo    **psfi;
1036         localref_table     *lrt;
1037         localref_table     *plrt;
1038         s4                  localframes;
1039         java_objectheader  *e;
1040
1041         /* get data structures from stack */
1042
1043         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1044         lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
1045                                                           sizeof(localref_table));
1046
1047         /* remove current stackframeinfo from chain */
1048
1049         psfi = STACKFRAMEINFO;
1050
1051         *psfi = sfi->prev;
1052
1053         /* release JNI local references tables for this thread */
1054
1055         lrt = LOCALREFTABLE;
1056
1057         /* release all current local frames */
1058
1059         for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1060                 /* get previous frame */
1061
1062                 plrt = lrt->prev;
1063
1064                 /* Clear all reference entries (only for tables allocated on
1065                    the Java heap). */
1066
1067                 if (localframes > 1)
1068                         MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1069
1070                 lrt->prev = NULL;
1071
1072                 /* set new local references table */
1073
1074                 lrt = plrt;
1075         }
1076
1077         /* now store the previous local frames in the thread structure */
1078
1079         LOCALREFTABLE = lrt;
1080
1081         /* get the exception and return it */
1082
1083         e = exceptions_get_and_clear_exception();
1084
1085         return e;
1086 }
1087
1088
1089 /* removecompilerstub **********************************************************
1090
1091    Deletes a compilerstub from memory (simply by freeing it).
1092
1093 *******************************************************************************/
1094
1095 void removecompilerstub(u1 *stub)
1096 {
1097         /* pass size 1 to keep the intern function happy */
1098
1099         CFREE((void *) stub, 1);
1100 }
1101
1102
1103 /* removenativestub ************************************************************
1104
1105    Removes a previously created native-stub from memory.
1106     
1107 *******************************************************************************/
1108
1109 void removenativestub(u1 *stub)
1110 {
1111         /* pass size 1 to keep the intern function happy */
1112
1113         CFREE((void *) stub, 1);
1114 }
1115
1116
1117 /* codegen_reg_of_var **********************************************************
1118
1119    This function determines a register, to which the result of an
1120    operation should go, when it is ultimatively intended to store the
1121    result in pseudoregister v.  If v is assigned to an actual
1122    register, this register will be returned.  Otherwise (when v is
1123    spilled) this function returns tempregnum.  If not already done,
1124    regoff and flags are set in the stack location.
1125        
1126    On ARM we have to check if a long/double variable is splitted
1127    across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1128    register of v for LOW_REG and the tempregnum for HIGH_REG in such
1129    cases.  (michi 2005/07/24)
1130
1131 *******************************************************************************/
1132
1133 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
1134 {
1135
1136 #if 0
1137         /* Do we have to generate a conditional move?  Yes, then always
1138            return the temporary register.  The real register is identified
1139            during the store. */
1140
1141         if (opcode & ICMD_CONDITION_MASK)
1142                 return tempregnum;
1143 #endif
1144
1145         if (!(v->flags & INMEMORY)) {
1146 #if defined(__ARM__) && defined(__ARMEL__)
1147                 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
1148                         return PACK_REGS(GET_LOW_REG(v->vv.regoff),
1149                                                          GET_HIGH_REG(tempregnum));
1150 #endif
1151 #if defined(__ARM__) && defined(__ARMEB__)
1152                 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
1153                         return PACK_REGS(GET_LOW_REG(tempregnum),
1154                                                          GET_HIGH_REG(v->vv.regoff));
1155 #endif
1156                 return v->vv.regoff;
1157         }
1158
1159 #if defined(ENABLE_STATISTICS)
1160         if (opt_stat)
1161                 count_spills_read++;
1162 #endif
1163
1164         return tempregnum;
1165 }
1166
1167 /* codegen_reg_of_dst **********************************************************
1168
1169    This function determines a register, to which the result of an
1170    operation should go, when it is ultimatively intended to store the
1171    result in iptr->dst.var.  If dst.var is assigned to an actual
1172    register, this register will be returned.  Otherwise (when it is
1173    spilled) this function returns tempregnum.  If not already done,
1174    regoff and flags are set in the stack location.
1175        
1176    On ARM we have to check if a long/double variable is splitted
1177    across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1178    register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
1179    cases.  (michi 2005/07/24)
1180
1181 *******************************************************************************/
1182
1183 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1184 {
1185         return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
1186 }
1187
1188
1189 #if defined(ENABLE_THREADS)
1190 void codegen_threadcritrestart(codegendata *cd, int offset)
1191 {
1192         cd->threadcritcurrent.mcoderestart = offset;
1193 }
1194
1195
1196 void codegen_threadcritstart(codegendata *cd, int offset)
1197 {
1198         cd->threadcritcurrent.mcodebegin = offset;
1199 }
1200
1201
1202 void codegen_threadcritstop(codegendata *cd, int offset)
1203 {
1204         cd->threadcritcurrent.next = cd->threadcrit;
1205         cd->threadcritcurrent.mcodeend = offset;
1206         cd->threadcrit = DNEW(codegen_critical_section_t);
1207         *(cd->threadcrit) = cd->threadcritcurrent;
1208         cd->threadcritcount++;
1209 }
1210 #endif
1211
1212
1213 /*
1214  * These are local overrides for various environment variables in Emacs.
1215  * Please do not remove this and leave it at the end of the file, where
1216  * Emacs will automagically detect them.
1217  * ---------------------------------------------------------------------
1218  * Local variables:
1219  * mode: c
1220  * indent-tabs-mode: t
1221  * c-basic-offset: 4
1222  * tab-width: 4
1223  * End:
1224  * vim:noexpandtab:sw=4:ts=4:
1225  */