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