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