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