cccf3acb10b7939a6b0fa47df146df5c0166a7a0
[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, 2007 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    All functions assume the following code area / data area layout:
26
27    +-----------+
28    |           |
29    | code area | code area grows to higher addresses
30    |           |
31    +-----------+ <-- start of procedure
32    |           |
33    | data area | data area grows to lower addresses
34    |           |
35    +-----------+
36
37    The functions first write into a temporary code/data area allocated by
38    "codegen_init". "codegen_finish" copies the code and data area into permanent
39    memory. All functions writing values into the data area return the offset
40    relative the begin of the code area (start of procedure).    
41
42    $Id: codegen-common.c 7918 2007-05-20 20:42:18Z michi $
43
44 */
45
46
47 #include "config.h"
48
49 #include <assert.h>
50 #include <string.h>
51
52 #include "vm/types.h"
53
54 #if defined(ENABLE_JIT)
55 /* this is required PATCHER_CALL_SIZE */
56 # include "codegen.h"
57 #endif
58
59 #if defined(__ARM__)
60 /* this is required for REG_SPLIT */
61 # include "md-abi.h"
62 #endif
63
64 #include "mm/memory.h"
65
66 #include "toolbox/avl.h"
67 #include "toolbox/list.h"
68 #include "toolbox/logging.h"
69
70 #include "native/jni.h"
71 #include "native/native.h"
72
73 #include "threads/threads-common.h"
74
75 #include "vm/builtin.h"
76 #include "vm/exceptions.h"
77 #include "vm/stringlocal.h"
78
79 #include "vm/jit/abi.h"
80 #include "vm/jit/asmpart.h"
81 #include "vm/jit/codegen-common.h"
82
83 #if defined(ENABLE_DISASSEMBLER)
84 # include "vm/jit/disass.h"
85 #endif
86
87 #include "vm/jit/dseg.h"
88 #include "vm/jit/emit-common.h"
89 #include "vm/jit/jit.h"
90 #include "vm/jit/md.h"
91 #include "vm/jit/replace.h"
92 #if defined(ENABLE_SSA)
93 # include "vm/jit/optimizing/lsra.h"
94 # include "vm/jit/optimizing/ssa.h"
95 #endif
96 #include "vm/jit/stacktrace.h"
97
98 #if defined(ENABLE_INTRP)
99 #include "vm/jit/intrp/intrp.h"
100 #endif
101
102 #include "vmcore/method.h"
103 #include "vmcore/options.h"
104
105 # include "vmcore/statistics.h"
106
107 #if defined(ENABLE_VMLOG)
108 #include <vmlog_cacao.h>
109 #endif
110
111
112 /* in this tree we store all method addresses *********************************/
113
114 static avl_tree_t *methodtree = NULL;
115 static s4 methodtree_comparator(const void *treenode, const void *node);
116
117
118 /* codegen_init ****************************************************************
119
120    TODO
121
122 *******************************************************************************/
123
124 void codegen_init(void)
125 {
126         /* this tree is global, not method specific */
127
128         if (!methodtree) {
129 #if defined(ENABLE_JIT)
130                 methodtree_element *mte;
131 #endif
132
133                 methodtree = avl_create(&methodtree_comparator);
134
135 #if defined(ENABLE_JIT)
136                 /* insert asm_vm_call_method */
137
138                 mte = NEW(methodtree_element);
139
140                 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
141                 mte->endpc   = (u1 *) (ptrint) asm_vm_call_method_end;
142
143                 avl_insert(methodtree, mte);
144 #endif /* defined(ENABLE_JIT) */
145         }
146 }
147
148
149 /* codegen_setup ***************************************************************
150
151    Allocates and initialises code area, data area and references.
152
153 *******************************************************************************/
154
155 void codegen_setup(jitdata *jd)
156 {
157         methodinfo  *m;
158         codegendata *cd;
159
160         /* get required compiler data */
161
162         m  = jd->m;
163         cd = jd->cd;
164
165         /* initialize members */
166
167         cd->flags        = 0;
168
169         cd->mcodebase    = DMNEW(u1, MCODEINITSIZE);
170         cd->mcodeend     = cd->mcodebase + MCODEINITSIZE;
171         cd->mcodesize    = MCODEINITSIZE;
172
173         /* initialize mcode variables */
174
175         cd->mcodeptr     = cd->mcodebase;
176         cd->lastmcodeptr = cd->mcodebase;
177
178 #if defined(ENABLE_INTRP)
179         /* native dynamic superinstructions variables */
180
181         if (opt_intrp) {
182                 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
183                 cd->ncodesize = NCODEINITSIZE;
184
185                 /* initialize ncode variables */
186         
187                 cd->ncodeptr = cd->ncodebase;
188
189                 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
190                 cd->superstarts = NULL;
191         }
192 #endif
193
194         cd->dseg           = NULL;
195         cd->dseglen        = 0;
196
197         cd->jumpreferences = NULL;
198
199 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
200         cd->datareferences = NULL;
201 #endif
202
203 /*      cd->patchrefs      = list_create_dump(OFFSET(patchref, linkage)); */
204         cd->patchrefs      = NULL;
205         cd->brancheslabel  = list_create_dump(OFFSET(branch_label_ref_t, linkage));
206         cd->listcritical   = list_create_dump(OFFSET(critical_section_ref_t, linkage));
207
208         cd->linenumberreferences = NULL;
209         cd->linenumbertablesizepos = 0;
210         cd->linenumbertablestartpos = 0;
211         cd->linenumbertab = 0;
212 }
213
214
215 /* codegen_reset ***************************************************************
216
217    Resets the codegen data structure so we can recompile the method.
218
219 *******************************************************************************/
220
221 static void codegen_reset(jitdata *jd)
222 {
223         codeinfo    *code;
224         codegendata *cd;
225         basicblock  *bptr;
226
227         /* get required compiler data */
228
229         code = jd->code;
230         cd   = jd->cd;
231
232         /* reset error flag */
233
234         cd->flags          &= ~CODEGENDATA_FLAG_ERROR;
235
236         /* reset some members, we reuse the code memory already allocated
237            as this should have almost the correct size */
238
239         cd->mcodeptr        = cd->mcodebase;
240         cd->lastmcodeptr    = cd->mcodebase;
241
242         cd->dseg            = NULL;
243         cd->dseglen         = 0;
244
245         cd->jumpreferences  = NULL;
246
247 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
248         cd->datareferences  = NULL;
249 #endif
250
251 /*      cd->patchrefs       = list_create_dump(OFFSET(patchref, linkage)); */
252         cd->patchrefs       = NULL;
253         cd->brancheslabel   = list_create_dump(OFFSET(branch_label_ref_t, linkage));
254         cd->listcritical    = list_create_dump(OFFSET(critical_section_ref_t, linkage));
255
256         cd->linenumberreferences    = NULL;
257         cd->linenumbertablesizepos  = 0;
258         cd->linenumbertablestartpos = 0;
259         cd->linenumbertab           = 0;
260         
261         /* We need to clear the mpc and the branch references from all
262            basic blocks as they will definitely change. */
263
264         for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
265                 bptr->mpc        = -1;
266                 bptr->branchrefs = NULL;
267         }
268
269 #if defined(ENABLE_REPLACEMENT)
270         code->rplpoints     = NULL;
271         code->rplpointcount = 0;
272         code->regalloc      = NULL;
273         code->regalloccount = 0;
274         code->globalcount   = 0;
275 #endif
276 }
277
278
279 /* codegen_generate ************************************************************
280
281    Generates the code for the currently compiled method.
282
283 *******************************************************************************/
284
285 bool codegen_generate(jitdata *jd)
286 {
287         codegendata *cd;
288
289         /* get required compiler data */
290
291         cd = jd->cd;
292
293         /* call the machine-dependent code generation function */
294
295         if (!codegen_emit(jd))
296                 return false;
297
298         /* check for an error */
299
300         if (CODEGENDATA_HAS_FLAG_ERROR(cd)) {
301                 /* check for long-branches flag, if it is set we recompile the
302                    method */
303
304 #if !defined(NDEBUG)
305         if (compileverbose)
306             log_message_method("Re-generating code: ", jd->m);
307 #endif
308
309                 /* XXX maybe we should tag long-branches-methods for recompilation */
310
311                 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
312                         /* we have to reset the codegendata structure first */
313
314                         codegen_reset(jd);
315
316                         /* and restart the compiler run */
317
318                         if (!codegen_emit(jd))
319                                 return false;
320                 }
321                 else {
322                         vm_abort("codegen_generate: unknown error occurred during codegen_emit: flags=%x\n", cd->flags);
323                 }
324
325 #if !defined(NDEBUG)
326         if (compileverbose)
327             log_message_method("Re-generating code done: ", jd->m);
328 #endif
329         }
330
331         /* reallocate the memory and finish the code generation */
332
333         codegen_finish(jd);
334
335         /* everything's ok */
336
337         return true;
338 }
339
340
341 /* codegen_close ***************************************************************
342
343    TODO
344
345 *******************************************************************************/
346
347 void codegen_close(void)
348 {
349         /* TODO: release avl tree on i386 and x86_64 */
350 }
351
352
353 /* codegen_increase ************************************************************
354
355    Doubles code area.
356
357 *******************************************************************************/
358
359 void codegen_increase(codegendata *cd)
360 {
361         u1 *oldmcodebase;
362
363         /* save old mcodebase pointer */
364
365         oldmcodebase = cd->mcodebase;
366
367         /* reallocate to new, doubled memory */
368
369         cd->mcodebase = DMREALLOC(cd->mcodebase,
370                                                           u1,
371                                                           cd->mcodesize,
372                                                           cd->mcodesize * 2);
373         cd->mcodesize *= 2;
374         cd->mcodeend   = cd->mcodebase + cd->mcodesize;
375
376         /* set new mcodeptr */
377
378         cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
379
380 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
381         /* adjust the pointer to the last patcher position */
382
383         if (cd->lastmcodeptr != NULL)
384                 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
385 #endif
386 }
387
388
389 /* codegen_ncode_increase ******************************************************
390
391    Doubles code area.
392
393 *******************************************************************************/
394
395 #if defined(ENABLE_INTRP)
396 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
397 {
398         u1 *oldncodebase;
399
400         /* save old ncodebase pointer */
401
402         oldncodebase = cd->ncodebase;
403
404         /* reallocate to new, doubled memory */
405
406         cd->ncodebase = DMREALLOC(cd->ncodebase,
407                                                           u1,
408                                                           cd->ncodesize,
409                                                           cd->ncodesize * 2);
410         cd->ncodesize *= 2;
411
412         /* return the new ncodeptr */
413
414         return (cd->ncodebase + (ncodeptr - oldncodebase));
415 }
416 #endif
417
418
419 /* codegen_add_branch_ref ******************************************************
420
421    Prepends an branch to the list.
422
423 *******************************************************************************/
424
425 void codegen_add_branch_ref(codegendata *cd, basicblock *target, s4 condition, s4 reg, u4 options)
426 {
427         branchref *br;
428         s4         branchmpc;
429
430         STATISTICS(count_branches_unresolved++);
431
432         /* calculate the mpc of the branch instruction */
433
434         branchmpc = cd->mcodeptr - cd->mcodebase;
435
436         br = DNEW(branchref);
437
438         br->branchmpc = branchmpc;
439         br->condition = condition;
440         br->reg       = reg;
441         br->options   = options;
442         br->next      = target->branchrefs;
443
444         target->branchrefs = br;
445 }
446
447
448 /* codegen_resolve_branchrefs **************************************************
449
450    Resolves and patches the branch references of a given basic block.
451
452 *******************************************************************************/
453
454 void codegen_resolve_branchrefs(codegendata *cd, basicblock *bptr)
455 {
456         branchref *br;
457         u1        *mcodeptr;
458
459         /* Save the mcodeptr because in the branch emitting functions
460            we generate code somewhere inside already generated code,
461            but we're still in the actual code generation phase. */
462
463         mcodeptr = cd->mcodeptr;
464
465         /* just to make sure */
466
467         assert(bptr->mpc >= 0);
468
469         for (br = bptr->branchrefs; br != NULL; br = br->next) {
470                 /* temporary set the mcodeptr */
471
472                 cd->mcodeptr = cd->mcodebase + br->branchmpc;
473
474                 /* emit_bccz and emit_branch emit the correct code, even if we
475                    pass condition == BRANCH_UNCONDITIONAL or reg == -1. */
476
477                 emit_bccz(cd, bptr, br->condition, br->reg, br->options);
478         }
479
480         /* restore mcodeptr */
481
482         cd->mcodeptr = mcodeptr;
483 }
484
485
486 /* codegen_branch_label_add ****************************************************
487
488    Append an branch to the label-branch list.
489
490 *******************************************************************************/
491
492 void codegen_branch_label_add(codegendata *cd, s4 label, s4 condition, s4 reg, u4 options)
493 {
494         list_t             *list;
495         branch_label_ref_t *br;
496         s4                  mpc;
497
498         /* get the label list */
499
500         list = cd->brancheslabel;
501         
502         /* calculate the current mpc */
503
504         mpc = cd->mcodeptr - cd->mcodebase;
505
506         br = DNEW(branch_label_ref_t);
507
508         br->mpc       = mpc;
509         br->label     = label;
510         br->condition = condition;
511         br->reg       = reg;
512         br->options   = options;
513
514         /* add the branch to the list */
515
516         list_add_last_unsynced(list, br);
517 }
518
519
520 /* codegen_add_patch_ref *******************************************************
521
522    Appends a new patcher reference to the list of patching positions.
523
524 *******************************************************************************/
525
526 void codegen_add_patch_ref(codegendata *cd, functionptr patcher, voidptr ref,
527                                                    s4 disp)
528 {
529         patchref *pr;
530         s4        branchmpc;
531
532         branchmpc = cd->mcodeptr - cd->mcodebase;
533
534         pr = DNEW(patchref);
535
536         pr->branchpos = branchmpc;
537         pr->disp      = disp;
538         pr->patcher   = patcher;
539         pr->ref       = ref;
540
541 /*      list_add_first(cd->patchrefs, pr); */
542         pr->next      = cd->patchrefs;
543         cd->patchrefs = pr;
544
545         /* Generate NOPs for opt_shownops. */
546
547         if (opt_shownops)
548                 PATCHER_NOPS;
549
550 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
551         /* On some architectures the patcher stub call instruction might
552            be longer than the actual instruction generated.  On this
553            architectures we store the last patcher call position and after
554            the basic block code generation is completed, we check the
555            range and maybe generate some nop's. */
556
557         cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
558 #endif
559 }
560
561
562 /* codegen_critical_section_new ************************************************
563
564    Allocates a new critical-section reference and adds it to the
565    critical-section list.
566
567 *******************************************************************************/
568
569 #if defined(ENABLE_THREADS)
570 void codegen_critical_section_new(codegendata *cd)
571 {
572         list_t                 *list;
573         critical_section_ref_t *csr;
574         s4                      mpc;
575
576         /* get the critical section list */
577
578         list = cd->listcritical;
579         
580         /* calculate the current mpc */
581
582         mpc = cd->mcodeptr - cd->mcodebase;
583
584         csr = DNEW(critical_section_ref_t);
585
586         /* We only can set restart right now, as start and end are set by
587            the following, corresponding functions. */
588
589         csr->start   = -1;
590         csr->end     = -1;
591         csr->restart = mpc;
592
593         /* add the branch to the list */
594
595         list_add_last_unsynced(list, csr);
596 }
597 #endif
598
599
600 /* codegen_critical_section_start **********************************************
601
602    Set the start-point of the current critical section (which is the
603    last element of the list).
604
605 *******************************************************************************/
606
607 #if defined(ENABLE_THREADS)
608 void codegen_critical_section_start(codegendata *cd)
609 {
610         list_t                 *list;
611         critical_section_ref_t *csr;
612         s4                      mpc;
613
614         /* get the critical section list */
615
616         list = cd->listcritical;
617         
618         /* calculate the current mpc */
619
620         mpc = cd->mcodeptr - cd->mcodebase;
621
622         /* get the current critical section */
623
624         csr = list_last_unsynced(list);
625
626         /* set the start point */
627
628         assert(csr->start == -1);
629
630         csr->start = mpc;
631 }
632 #endif
633
634
635 /* codegen_critical_section_end ************************************************
636
637    Set the end-point of the current critical section (which is the
638    last element of the list).
639
640 *******************************************************************************/
641
642 #if defined(ENABLE_THREADS)
643 void codegen_critical_section_end(codegendata *cd)
644 {
645         list_t                 *list;
646         critical_section_ref_t *csr;
647         s4                      mpc;
648
649         /* get the critical section list */
650
651         list = cd->listcritical;
652         
653         /* calculate the current mpc */
654
655         mpc = cd->mcodeptr - cd->mcodebase;
656
657         /* get the current critical section */
658
659         csr = list_last_unsynced(list);
660
661         /* set the end point */
662
663         assert(csr->end == -1);
664
665         csr->end = mpc;
666 }
667 #endif
668
669
670 /* codegen_critical_section_finish *********************************************
671
672    Finish the critical sections, create the critical section nodes for
673    the AVL tree and insert them into the tree.
674
675 *******************************************************************************/
676
677 #if defined(ENABLE_THREADS)
678 static void codegen_critical_section_finish(jitdata *jd)
679 {
680         codeinfo    *code;
681         codegendata *cd;
682         list_t                  *list;
683         critical_section_ref_t  *csr;
684         critical_section_node_t *csn;
685
686         /* get required compiler data */
687
688         code = jd->code;
689         cd   = jd->cd;
690
691         /* get the critical section list */
692
693         list = cd->listcritical;
694
695         /* iterate over all critical sections */
696
697         for (csr = list_first_unsynced(list); csr != NULL;
698                  csr = list_next_unsynced(list, csr)) {
699                 /* check if all points are set */
700
701                 assert(csr->start   != -1);
702                 assert(csr->end     != -1);
703                 assert(csr->restart != -1);
704
705                 /* allocate tree node */
706
707                 csn = NEW(critical_section_node_t);
708
709                 csn->start   = code->entrypoint + csr->start;
710                 csn->end     = code->entrypoint + csr->end;
711                 csn->restart = code->entrypoint + csr->restart;
712
713                 /* insert into the tree */
714
715                 critical_section_register(csn);
716         }
717 }
718 #endif
719
720
721 /* methodtree_comparator *******************************************************
722
723    Comparator function used for the AVL tree of methods.
724
725    ARGUMENTS:
726       treenode....the node from the tree
727       node........the node to compare to the tree-node
728
729 *******************************************************************************/
730
731 static s4 methodtree_comparator(const void *treenode, const void *node)
732 {
733         methodtree_element *mte;
734         methodtree_element *mtepc;
735
736         mte   = (methodtree_element *) treenode;
737         mtepc = (methodtree_element *) node;
738
739         /* compare both startpc and endpc of pc, even if they have the same value,
740            otherwise the avl_probe sometimes thinks the element is already in the
741            tree */
742
743 #ifdef __S390__
744         /* On S390 addresses are 31 bit. Compare only 31 bits of value.
745          */
746 #       define ADDR_MASK(a) ((a) & 0x7FFFFFFF)
747 #else
748 #       define ADDR_MASK(a) (a)
749 #endif
750
751         if (ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->startpc) &&
752                 ADDR_MASK((long) mtepc->startpc) <= ADDR_MASK((long) mte->endpc) &&
753                 ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->endpc) &&
754                 ADDR_MASK((long) mtepc->endpc) <= ADDR_MASK((long) mte->endpc)) {
755                 return 0;
756
757         } else if (ADDR_MASK((long) mtepc->startpc) < ADDR_MASK((long) mte->startpc)) {
758                 return -1;
759
760         } else {
761                 return 1;
762         }
763
764 #       undef ADDR_MASK
765 }
766
767
768 /* codegen_insertmethod ********************************************************
769
770    Insert the machine code range of a method into the AVL tree of methods.
771
772 *******************************************************************************/
773
774 void codegen_insertmethod(u1 *startpc, u1 *endpc)
775 {
776         methodtree_element *mte;
777
778         /* allocate new method entry */
779
780         mte = NEW(methodtree_element);
781
782         mte->startpc = startpc;
783         mte->endpc   = endpc;
784
785         /* this function does not return an error, but asserts for
786            duplicate entries */
787
788         avl_insert(methodtree, mte);
789 }
790
791
792 /* codegen_get_pv_from_pc ******************************************************
793
794    Find the PV for the given PC by searching in the AVL tree of
795    methods.
796
797 *******************************************************************************/
798
799 u1 *codegen_get_pv_from_pc(u1 *pc)
800 {
801         methodtree_element  mtepc;
802         methodtree_element *mte;
803
804         /* allocation of the search structure on the stack is much faster */
805
806         mtepc.startpc = pc;
807         mtepc.endpc   = pc;
808
809         mte = avl_find(methodtree, &mtepc);
810
811         if (mte == NULL) {
812                 /* No method was found.  Let's dump a stacktrace. */
813
814 #if defined(ENABLE_VMLOG)
815                 vmlog_cacao_signl("SIGSEGV");
816 #endif
817
818                 log_println("We received a SIGSEGV and tried to handle it, but we were");
819                 log_println("unable to find a Java method at:");
820                 log_println("");
821 #if SIZEOF_VOID_P == 8
822                 log_println("PC=0x%016lx", pc);
823 #else
824                 log_println("PC=0x%08x", pc);
825 #endif
826                 log_println("");
827                 log_println("Dumping the current stacktrace:");
828
829 #if defined(ENABLE_THREADS)
830                 /* XXX michi: This should be available even without threads! */
831                 threads_print_stacktrace();
832 #endif
833
834                 vm_abort("Exiting...");
835         }
836
837         return mte->startpc;
838 }
839
840
841 /* codegen_get_pv_from_pc_nocheck **********************************************
842
843    Find the PV for the given PC by searching in the AVL tree of
844    methods.  This method does not check the return value and is used
845    by the profiler.
846
847 *******************************************************************************/
848
849 u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
850 {
851         methodtree_element  mtepc;
852         methodtree_element *mte;
853
854         /* allocation of the search structure on the stack is much faster */
855
856         mtepc.startpc = pc;
857         mtepc.endpc   = pc;
858
859         mte = avl_find(methodtree, &mtepc);
860
861         if (mte == NULL)
862                 return NULL;
863         else
864                 return mte->startpc;
865 }
866
867
868 /* codegen_set_replacement_point_notrap ****************************************
869
870    Record the position of a non-trappable replacement point.
871
872 *******************************************************************************/
873
874 #if defined(ENABLE_REPLACEMENT)
875 #if !defined(NDEBUG)
876 void codegen_set_replacement_point_notrap(codegendata *cd, s4 type)
877 #else
878 void codegen_set_replacement_point_notrap(codegendata *cd)
879 #endif
880 {
881         assert(cd->replacementpoint);
882         assert(cd->replacementpoint->type == type);
883         assert(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP);
884
885         cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
886
887         cd->replacementpoint++;
888 }
889 #endif /* defined(ENABLE_REPLACEMENT) */
890
891
892 /* codegen_set_replacement_point ***********************************************
893
894    Record the position of a trappable replacement point.
895
896 *******************************************************************************/
897
898 #if defined(ENABLE_REPLACEMENT)
899 #if !defined(NDEBUG)
900 void codegen_set_replacement_point(codegendata *cd, s4 type)
901 #else
902 void codegen_set_replacement_point(codegendata *cd)
903 #endif
904 {
905         assert(cd->replacementpoint);
906         assert(cd->replacementpoint->type == type);
907         assert(!(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP));
908
909         cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
910
911         cd->replacementpoint++;
912
913         /* XXX assert(cd->lastmcodeptr <= cd->mcodeptr); */
914
915         cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
916 }
917 #endif /* defined(ENABLE_REPLACEMENT) */
918
919
920 /* codegen_finish **************************************************************
921
922    Finishes the code generation. A new memory, large enough for both
923    data and code, is allocated and data and code are copied together
924    to their final layout, unresolved jumps are resolved, ...
925
926 *******************************************************************************/
927
928 void codegen_finish(jitdata *jd)
929 {
930         codeinfo    *code;
931         codegendata *cd;
932         s4           mcodelen;
933 #if defined(ENABLE_INTRP)
934         s4           ncodelen;
935 #endif
936         s4           alignedmcodelen;
937         jumpref     *jr;
938         u1          *epoint;
939         s4           alignedlen;
940
941         /* get required compiler data */
942
943         code = jd->code;
944         cd   = jd->cd;
945
946         /* prevent compiler warning */
947
948 #if defined(ENABLE_INTRP)
949         ncodelen = 0;
950 #endif
951
952         /* calculate the code length */
953
954         mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
955
956 #if defined(ENABLE_STATISTICS)
957         if (opt_stat) {
958                 count_code_len += mcodelen;
959                 count_data_len += cd->dseglen;
960         }
961 #endif
962
963         alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
964
965 #if defined(ENABLE_INTRP)
966         if (opt_intrp)
967                 ncodelen = cd->ncodeptr - cd->ncodebase;
968         else {
969                 ncodelen = 0; /* avoid compiler warning */
970         }
971 #endif
972
973         cd->dseglen = MEMORY_ALIGN(cd->dseglen, MAX_ALIGN);
974         alignedlen = alignedmcodelen + cd->dseglen;
975
976 #if defined(ENABLE_INTRP)
977         if (opt_intrp) {
978                 alignedlen += ncodelen;
979         }
980 #endif
981
982         /* allocate new memory */
983
984         code->mcodelength = mcodelen + cd->dseglen;
985         code->mcode       = CNEW(u1, alignedlen);
986
987         /* set the entrypoint of the method */
988         
989         assert(code->entrypoint == NULL);
990         code->entrypoint = epoint = (code->mcode + cd->dseglen);
991
992         /* fill the data segment (code->entrypoint must already be set!) */
993
994         dseg_finish(jd);
995
996         /* copy code to the new location */
997
998         MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
999
1000 #if defined(ENABLE_INTRP)
1001         /* relocate native dynamic superinstruction code (if any) */
1002
1003         if (opt_intrp) {
1004                 cd->mcodebase = code->entrypoint;
1005
1006                 if (ncodelen > 0) {
1007                         u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
1008
1009                         MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
1010
1011                         /* flush the instruction and data caches */
1012
1013                         md_cacheflush(ncodebase, ncodelen);
1014
1015                         /* set some cd variables for dynamic_super_rerwite */
1016
1017                         cd->ncodebase = ncodebase;
1018
1019                 } else {
1020                         cd->ncodebase = NULL;
1021                 }
1022
1023                 dynamic_super_rewrite(cd);
1024         }
1025 #endif
1026
1027         /* jump table resolving */
1028
1029         for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
1030                 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
1031                         (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
1032
1033         /* line number table resolving */
1034         {
1035                 linenumberref *lr;
1036                 ptrint lrtlen = 0;
1037                 ptrint target;
1038
1039                 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
1040                         lrtlen++;
1041                         target = lr->targetmpc;
1042                         /* if the entry contains an mcode pointer (normal case), resolve it */
1043                         /* (see doc/inlining_stacktrace.txt for details)                    */
1044                         if (lr->linenumber >= -2) {
1045                             target += (ptrint) epoint;
1046                         }
1047                         *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) = 
1048                                 (functionptr) target;
1049                 }
1050                 
1051                 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
1052                         (functionptr) ((ptrint) epoint + cd->linenumbertab);
1053
1054                 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
1055         }
1056
1057 #if defined(ENABLE_REPLACEMENT)
1058         /* replacement point resolving */
1059         {
1060                 int i;
1061                 rplpoint *rp;
1062
1063                 code->replacementstubs += (ptrint) epoint;
1064
1065                 rp = code->rplpoints;
1066                 for (i=0; i<code->rplpointcount; ++i, ++rp) {
1067                         rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
1068                 }
1069         }
1070 #endif /* defined(ENABLE_REPLACEMENT) */
1071
1072         /* add method into methodtree to find the entrypoint */
1073
1074         codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
1075
1076 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
1077         /* resolve data segment references */
1078
1079         dseg_resolve_datareferences(jd);
1080 #endif
1081
1082 #if defined(ENABLE_THREADS)
1083         /* create cirtical sections */
1084
1085         codegen_critical_section_finish(jd);
1086 #endif
1087
1088         /* flush the instruction and data caches */
1089
1090         md_cacheflush(code->mcode, code->mcodelength);
1091 }
1092
1093
1094 /* codegen_generate_stub_compiler **********************************************
1095
1096    Wrapper for codegen_emit_stub_compiler.
1097
1098    Returns:
1099        pointer to the compiler stub code.
1100
1101 *******************************************************************************/
1102
1103 u1 *codegen_generate_stub_compiler(methodinfo *m)
1104 {
1105         jitdata     *jd;
1106         codegendata *cd;
1107         ptrint      *d;                     /* pointer to data memory             */
1108         u1          *c;                     /* pointer to code memory             */
1109         s4           dumpsize;
1110
1111         /* mark dump memory */
1112
1113         dumpsize = dump_size();
1114
1115         /* allocate required data structures */
1116
1117         jd = DNEW(jitdata);
1118
1119         jd->m     = m;
1120         jd->cd    = DNEW(codegendata);
1121         jd->flags = 0;
1122
1123         /* get required compiler data */
1124
1125         cd = jd->cd;
1126
1127         /* allocate code memory */
1128
1129         c = CNEW(u1, 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE);
1130
1131         /* set pointers correctly */
1132
1133         d = (ptrint *) c;
1134
1135         cd->mcodebase = c;
1136
1137         c = c + 3 * SIZEOF_VOID_P;
1138         cd->mcodeptr = c;
1139
1140         /* NOTE: The codeinfo pointer is actually a pointer to the
1141            methodinfo (this fakes a codeinfo structure). */
1142
1143         d[0] = (ptrint) asm_call_jit_compiler;
1144         d[1] = (ptrint) m;
1145         d[2] = (ptrint) &d[1];                                    /* fake code->m */
1146
1147         /* call the emit function */
1148
1149         codegen_emit_stub_compiler(jd);
1150
1151 #if defined(ENABLE_STATISTICS)
1152         if (opt_stat)
1153                 count_cstub_len += 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE;
1154 #endif
1155
1156         /* flush caches */
1157
1158         md_cacheflush(cd->mcodebase, 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE);
1159
1160         /* release dump memory */
1161
1162         dump_release(dumpsize);
1163
1164         /* return native stub code */
1165
1166         return c;
1167 }
1168
1169
1170 /* codegen_generate_stub_builtin ***********************************************
1171
1172    Wrapper for codegen_emit_stub_builtin.
1173
1174    Returns:
1175        Pointer to the entrypoint of the stub.
1176
1177 *******************************************************************************/
1178
1179 void codegen_generate_stub_builtin(builtintable_entry *bte)
1180 {
1181         jitdata  *jd;
1182         codeinfo *code;
1183         s4        dumpsize;
1184
1185         /* mark dump memory */
1186
1187         dumpsize = dump_size();
1188
1189         jd = DNEW(jitdata);
1190
1191         jd->m     = NULL;
1192         jd->cd    = DNEW(codegendata);
1193         jd->rd    = NULL;
1194         jd->flags = 0;
1195
1196         /* Allocate codeinfo memory from the heap as we need to keep them. */
1197
1198         jd->code  = code_codeinfo_new(NULL);
1199
1200         /* get required compiler data */
1201
1202         code = jd->code;
1203
1204         /* setup code generation stuff */
1205
1206         codegen_setup(jd);
1207
1208         /* generate the code */
1209
1210 #if defined(ENABLE_JIT)
1211 # if defined(ENABLE_INTRP)
1212         if (!opt_intrp)
1213 # endif
1214                 codegen_emit_stub_builtin(jd, bte);
1215 #endif
1216
1217         /* reallocate the memory and finish the code generation */
1218
1219         codegen_finish(jd);
1220
1221         /* set the stub entry point in the builtin table */
1222
1223         bte->stub = code->entrypoint;
1224
1225 #if defined(ENABLE_STATISTICS)
1226         if (opt_stat)
1227                 size_stub_native += code->mcodelength;
1228 #endif
1229
1230         /* release memory */
1231
1232         dump_release(dumpsize);
1233 }
1234
1235
1236 /* codegen_generate_stub_native ************************************************
1237
1238    Wrapper for codegen_emit_stub_native.
1239
1240    Returns:
1241        the codeinfo representing the stub code.
1242
1243 *******************************************************************************/
1244
1245 codeinfo *codegen_generate_stub_native(methodinfo *m, functionptr f)
1246 {
1247         jitdata     *jd;
1248         codeinfo    *code;
1249         s4           dumpsize;
1250         methoddesc  *md;
1251         methoddesc  *nmd;       
1252         s4           nativeparams;
1253
1254         /* mark dump memory */
1255
1256         dumpsize = dump_size();
1257
1258         jd = DNEW(jitdata);
1259
1260         jd->m     = m;
1261         jd->cd    = DNEW(codegendata);
1262         jd->rd    = DNEW(registerdata);
1263         jd->flags = 0;
1264
1265         /* Allocate codeinfo memory from the heap as we need to keep them. */
1266
1267         jd->code  = code_codeinfo_new(m); /* XXX check allocation */
1268
1269         /* get required compiler data */
1270
1271         code = jd->code;
1272
1273         /* set the flags for the current JIT run */
1274
1275 #if defined(ENABLE_PROFILING)
1276         if (opt_prof)
1277                 jd->flags |= JITDATA_FLAG_INSTRUMENT;
1278 #endif
1279
1280         if (opt_verbosecall)
1281                 jd->flags |= JITDATA_FLAG_VERBOSECALL;
1282
1283         /* setup code generation stuff */
1284
1285 #if defined(ENABLE_JIT)
1286 # if defined(ENABLE_INTRP)
1287         if (!opt_intrp)
1288 # endif
1289                 reg_setup(jd);
1290 #endif
1291
1292         codegen_setup(jd);
1293
1294         /* create new method descriptor with additional native parameters */
1295
1296         md = m->parseddesc;
1297         nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
1298         
1299         nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
1300                                                            md->paramcount * sizeof(typedesc) +
1301                                                            nativeparams * sizeof(typedesc));
1302
1303         nmd->paramcount = md->paramcount + nativeparams;
1304
1305         nmd->params = DMNEW(paramdesc, nmd->paramcount);
1306
1307         nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer            */
1308
1309         if (m->flags & ACC_STATIC)
1310                 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer              */
1311
1312         MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
1313                   md->paramcount);
1314
1315 #if defined(ENABLE_JIT)
1316 # if defined(ENABLE_INTRP)
1317         if (!opt_intrp)
1318 # endif
1319                 /* pre-allocate the arguments for the native ABI */
1320
1321                 md_param_alloc_native(nmd);
1322 #endif
1323
1324         /* generate the code */
1325
1326 #if defined(ENABLE_JIT)
1327 # if defined(ENABLE_INTRP)
1328         if (opt_intrp)
1329                 intrp_createnativestub(f, jd, nmd);
1330         else
1331 # endif
1332                 codegen_emit_stub_native(jd, nmd, f);
1333 #else
1334         intrp_createnativestub(f, jd, nmd);
1335 #endif
1336
1337         /* reallocate the memory and finish the code generation */
1338
1339         codegen_finish(jd);
1340
1341 #if defined(ENABLE_STATISTICS)
1342         /* must be done after codegen_finish() */
1343
1344         if (opt_stat)
1345                 size_stub_native += code->mcodelength;
1346 #endif
1347
1348 #if !defined(NDEBUG)
1349         /* disassemble native stub */
1350
1351         if (opt_shownativestub) {
1352 #if defined(ENABLE_DISASSEMBLER)
1353                 codegen_disassemble_nativestub(m,
1354                                                                            (u1 *) (ptrint) code->entrypoint,
1355                                                                            (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
1356 #endif
1357
1358                 /* show data segment */
1359
1360                 if (opt_showddatasegment)
1361                         dseg_display(jd);
1362         }
1363 #endif /* !defined(NDEBUG) */
1364
1365         /* release memory */
1366
1367         dump_release(dumpsize);
1368
1369         /* return native stub code */
1370
1371         return code;
1372 }
1373
1374
1375 /* codegen_disassemble_nativestub **********************************************
1376
1377    Disassembles the generated native stub.
1378
1379 *******************************************************************************/
1380
1381 #if defined(ENABLE_DISASSEMBLER)
1382 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
1383 {
1384         printf("Native stub: ");
1385         utf_fprint_printable_ascii_classname(stdout, m->class->name);
1386         printf(".");
1387         utf_fprint_printable_ascii(stdout, m->name);
1388         utf_fprint_printable_ascii(stdout, m->descriptor);
1389         printf("\n\nLength: %d\n\n", (s4) (end - start));
1390
1391         DISASSEMBLE(start, end);
1392 }
1393 #endif
1394
1395
1396 /* codegen_stub_builtin_enter **************************************************
1397
1398    Prepares the stuff required for a builtin function call:
1399
1400    - adds a stackframe info structure to the chain, for stacktraces
1401
1402    The layout of the builtin stub stackframe should look like this:
1403
1404    +---------------------------+ <- SP (of parent Java function)
1405    | return address            |
1406    +---------------------------+
1407    |                           |
1408    | stackframe info structure |
1409    |                           |
1410    +---------------------------+
1411    |                           |
1412    | arguments (if any)        |
1413    |                           |
1414    +---------------------------+ <- SP (native stub)
1415
1416 *******************************************************************************/
1417
1418 void codegen_stub_builtin_enter(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
1419 {
1420         stackframeinfo *sfi;
1421
1422         /* get data structures from stack */
1423
1424         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1425
1426         /* add a stackframeinfo to the chain */
1427
1428         stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1429
1430 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1431         /* set the native world flag */
1432
1433         THREADOBJECT->flags |= THREAD_FLAG_IN_NATIVE;
1434 #endif
1435 }
1436
1437
1438 /* codegen_stub_builtin_exit ***************************************************
1439
1440    Removes the stuff required for a builtin function call.
1441
1442 *******************************************************************************/
1443
1444 void codegen_stub_builtin_exit(u1 *datasp)
1445 {
1446         stackframeinfo     *sfi;
1447         stackframeinfo    **psfi;
1448
1449         /* get data structures from stack */
1450
1451         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1452
1453         /* remove current stackframeinfo from chain */
1454
1455         psfi = &STACKFRAMEINFO;
1456
1457         *psfi = sfi->prev;
1458
1459 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1460         /* clear the native world flag */
1461
1462         THREADOBJECT->flags &= ~THREAD_FLAG_IN_NATIVE;
1463 #endif
1464 }
1465
1466
1467 /* codegen_start_native_call ***************************************************
1468
1469    Prepares the stuff required for a native (JNI) function call:
1470
1471    - adds a stackframe info structure to the chain, for stacktraces
1472    - prepares the local references table on the stack
1473
1474    The layout of the native stub stackframe should look like this:
1475
1476    +---------------------------+ <- SP (of parent Java function)
1477    | return address            |
1478    +---------------------------+
1479    |                           |
1480    | stackframe info structure |
1481    |                           |
1482    +---------------------------+
1483    |                           |
1484    | local references table    |
1485    |                           |
1486    +---------------------------+
1487    |                           |
1488    | arguments (if any)        |
1489    |                           |
1490    +---------------------------+ <- SP (native stub)
1491
1492 *******************************************************************************/
1493
1494 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
1495 {
1496         stackframeinfo *sfi;
1497         localref_table *lrt;
1498
1499         /* get data structures from stack */
1500
1501         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1502         lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
1503                                                           sizeof(localref_table));
1504
1505         /* add a stackframeinfo to the chain */
1506
1507         stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1508
1509 #if defined(ENABLE_JNI)
1510         /* add current JNI local references table to this thread */
1511
1512         lrt->capacity    = LOCALREFTABLE_CAPACITY;
1513         lrt->used        = 0;
1514         lrt->localframes = 1;
1515         lrt->prev        = LOCALREFTABLE;
1516
1517         /* clear the references array (memset is faster the a for-loop) */
1518
1519         MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1520
1521         LOCALREFTABLE = lrt;
1522 #endif
1523
1524 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1525         /* set the native world flag */
1526
1527         THREADOBJECT->flags |= THREAD_FLAG_IN_NATIVE;
1528 #endif
1529 }
1530
1531
1532 /* codegen_finish_native_call **************************************************
1533
1534    Removes the stuff required for a native (JNI) function call.
1535    Additionally it checks for an exceptions and in case, get the
1536    exception object and clear the pointer.
1537
1538 *******************************************************************************/
1539
1540 java_objectheader *codegen_finish_native_call(u1 *datasp)
1541 {
1542         stackframeinfo     *sfi;
1543         stackframeinfo    **psfi;
1544 #if defined(ENABLE_JNI)
1545         localref_table     *lrt;
1546         localref_table     *plrt;
1547         s4                  localframes;
1548 #endif
1549         java_objectheader  *e;
1550
1551         /* get data structures from stack */
1552
1553         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1554
1555 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
1556         /* clear the native world flag */
1557
1558         THREADOBJECT->flags &= ~THREAD_FLAG_IN_NATIVE;
1559 #endif
1560
1561         /* remove current stackframeinfo from chain */
1562
1563         psfi = &STACKFRAMEINFO;
1564
1565         *psfi = sfi->prev;
1566
1567 #if defined(ENABLE_JNI)
1568         /* release JNI local references tables for this thread */
1569
1570         lrt = LOCALREFTABLE;
1571
1572         /* release all current local frames */
1573
1574         for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1575                 /* get previous frame */
1576
1577                 plrt = lrt->prev;
1578
1579                 /* Clear all reference entries (only for tables allocated on
1580                    the Java heap). */
1581
1582                 if (localframes > 1)
1583                         MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1584
1585                 lrt->prev = NULL;
1586
1587                 /* set new local references table */
1588
1589                 lrt = plrt;
1590         }
1591
1592         /* now store the previous local frames in the thread structure */
1593
1594         LOCALREFTABLE = lrt;
1595 #endif
1596
1597         /* get the exception and return it */
1598
1599         e = exceptions_get_and_clear_exception();
1600
1601         return e;
1602 }
1603
1604
1605 /* removecompilerstub **********************************************************
1606
1607    Deletes a compilerstub from memory (simply by freeing it).
1608
1609 *******************************************************************************/
1610
1611 void removecompilerstub(u1 *stub)
1612 {
1613         /* pass size 1 to keep the intern function happy */
1614
1615         CFREE((void *) stub, 1);
1616 }
1617
1618
1619 /* removenativestub ************************************************************
1620
1621    Removes a previously created native-stub from memory.
1622     
1623 *******************************************************************************/
1624
1625 void removenativestub(u1 *stub)
1626 {
1627         /* pass size 1 to keep the intern function happy */
1628
1629         CFREE((void *) stub, 1);
1630 }
1631
1632
1633 /* codegen_reg_of_var **********************************************************
1634
1635    This function determines a register, to which the result of an
1636    operation should go, when it is ultimatively intended to store the
1637    result in pseudoregister v.  If v is assigned to an actual
1638    register, this register will be returned.  Otherwise (when v is
1639    spilled) this function returns tempregnum.  If not already done,
1640    regoff and flags are set in the stack location.
1641        
1642    On ARM we have to check if a long/double variable is splitted
1643    across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1644    register of v for LOW_REG and the tempregnum for HIGH_REG in such
1645    cases.  (michi 2005/07/24)
1646
1647 *******************************************************************************/
1648
1649 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
1650 {
1651
1652 #if 0
1653         /* Do we have to generate a conditional move?  Yes, then always
1654            return the temporary register.  The real register is identified
1655            during the store. */
1656
1657         if (opcode & ICMD_CONDITION_MASK)
1658                 return tempregnum;
1659 #endif
1660
1661         if (!(v->flags & INMEMORY)) {
1662 #if defined(__ARM__) && defined(__ARMEL__)
1663                 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
1664                         return PACK_REGS(GET_LOW_REG(v->vv.regoff),
1665                                                          GET_HIGH_REG(tempregnum));
1666 #endif
1667 #if defined(__ARM__) && defined(__ARMEB__)
1668                 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
1669                         return PACK_REGS(GET_LOW_REG(tempregnum),
1670                                                          GET_HIGH_REG(v->vv.regoff));
1671 #endif
1672                 return v->vv.regoff;
1673         }
1674
1675 #if defined(ENABLE_STATISTICS)
1676         if (opt_stat)
1677                 count_spills_read++;
1678 #endif
1679
1680         return tempregnum;
1681 }
1682
1683 /* codegen_reg_of_dst **********************************************************
1684
1685    This function determines a register, to which the result of an
1686    operation should go, when it is ultimatively intended to store the
1687    result in iptr->dst.var.  If dst.var is assigned to an actual
1688    register, this register will be returned.  Otherwise (when it is
1689    spilled) this function returns tempregnum.  If not already done,
1690    regoff and flags are set in the stack location.
1691        
1692    On ARM we have to check if a long/double variable is splitted
1693    across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1694    register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
1695    cases.  (michi 2005/07/24)
1696
1697 *******************************************************************************/
1698
1699 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1700 {
1701         return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
1702 }
1703
1704
1705 /* codegen_emit_phi_moves ****************************************************
1706
1707    Emits phi moves at the end of the basicblock.
1708
1709 *******************************************************************************/
1710
1711 #if defined(ENABLE_SSA)
1712 void codegen_emit_phi_moves(jitdata *jd, basicblock *bptr)
1713 {
1714         int lt_d,lt_s,i;
1715         lsradata *ls;
1716         codegendata *cd;
1717         varinfo *s, *d;
1718         instruction tmp_i;
1719
1720         cd = jd->cd;
1721         ls = jd->ls;
1722
1723         MCODECHECK(512);
1724
1725         /* Moves from phi functions with highest indices have to be */
1726         /* inserted first, since this is the order as is used for   */
1727         /* conflict resolution */
1728
1729         for(i = ls->num_phi_moves[bptr->nr] - 1; i >= 0 ; i--) {
1730                 lt_d = ls->phi_moves[bptr->nr][i][0];
1731                 lt_s = ls->phi_moves[bptr->nr][i][1];
1732 #if defined(SSA_DEBUG_VERBOSE)
1733                 if (compileverbose)
1734                         printf("BB %3i Move %3i <- %3i ", bptr->nr, lt_d, lt_s);
1735 #endif
1736                 if (lt_s == UNUSED) {
1737 #if defined(SSA_DEBUG_VERBOSE)
1738                 if (compileverbose)
1739                         printf(" ... not processed \n");
1740 #endif
1741                         continue;
1742                 }
1743                         
1744                 d = VAR(ls->lifetime[lt_d].v_index);
1745                 s = VAR(ls->lifetime[lt_s].v_index);
1746                 
1747
1748                 if (d->type == -1) {
1749 #if defined(SSA_DEBUG_VERBOSE)
1750                         if (compileverbose)
1751                                 printf("...returning - phi lifetimes where joined\n");
1752 #endif
1753                         return;
1754                 }
1755
1756                 if (s->type == -1) {
1757 #if defined(SSA_DEBUG_VERBOSE)
1758                         if (compileverbose)
1759                                 printf("...returning - phi lifetimes where joined\n");
1760 #endif
1761                         return;
1762                 }
1763
1764                 tmp_i.opc = 0;
1765                 tmp_i.s1.varindex = ls->lifetime[lt_s].v_index;
1766                 tmp_i.dst.varindex = ls->lifetime[lt_d].v_index;
1767                 emit_copy(jd, &tmp_i);
1768
1769 #if defined(SSA_DEBUG_VERBOSE)
1770                 if (compileverbose) {
1771                         if (IS_INMEMORY(d->flags) && IS_INMEMORY(s->flags)) {
1772                                 /* mem -> mem */
1773                                 printf("M%3i <- M%3i",d->vv.regoff,s->vv.regoff);
1774                         }
1775                         else if (IS_INMEMORY(s->flags)) {
1776                                 /* mem -> reg */
1777                                 printf("R%3i <- M%3i",d->vv.regoff,s->vv.regoff);
1778                         }
1779                         else if (IS_INMEMORY(d->flags)) {
1780                                 /* reg -> mem */
1781                                 printf("M%3i <- R%3i",d->vv.regoff,s->vv.regoff);
1782                         }
1783                         else {
1784                                 /* reg -> reg */
1785                                 printf("R%3i <- R%3i",d->vv.regoff,s->vv.regoff);
1786                         }
1787                         printf("\n");
1788                 }
1789 #endif /* defined(SSA_DEBUG_VERBOSE) */
1790         }
1791 }
1792 #endif /* defined(ENABLE_SSA) */
1793
1794
1795
1796 /*
1797  * These are local overrides for various environment variables in Emacs.
1798  * Please do not remove this and leave it at the end of the file, where
1799  * Emacs will automagically detect them.
1800  * ---------------------------------------------------------------------
1801  * Local variables:
1802  * mode: c
1803  * indent-tabs-mode: t
1804  * c-basic-offset: 4
1805  * tab-width: 4
1806  * End:
1807  * vim:noexpandtab:sw=4:ts=4:
1808  */