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