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