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