* powerpc warning fixes
[cacao.git] / src / vm / jit / codegen.inc
1 /* src/vm/jit/codegen.inc - architecture independent code generator
2
3    Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    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., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Reinhard Grafl
28             Andreas  Krall
29
30    Changes: Christian Thalinger
31             Joseph Wenninger
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.inc 2694 2005-06-14 18:35:52Z twisti $
51
52 */
53
54
55 #include <assert.h>
56 #include <string.h>
57
58 #include "disass.h"
59
60 #include "mm/memory.h"
61 #include "toolbox/avl.h"
62 #include "toolbox/logging.h"
63 #include "native/native.h"
64
65 #if defined(USE_THREADS)
66 # if defined(NATIVE_THREADS)
67 #  include "threads/native/threads.h"
68 # else
69 #  include "threads/green/threads.h"
70 # endif
71 #endif
72
73 #include "vm/exceptions.h"
74 #include "vm/options.h"
75 #include "vm/statistics.h"
76 #include "vm/jit/codegen.inc.h"
77
78 #undef JWDEBUG_X86
79
80 #ifdef JWDEBUG_X86
81 #include <execinfo.h>
82 #endif
83
84 /* in this tree we store all method addresses *********************************/
85
86 #if defined(__I386__) || defined(__X86_64__)
87 static struct avl_table *methodtree = NULL;
88 static int methodtree_comparator(const void *pc, const void *element,
89                                                                  void *param);
90 #endif
91
92
93 /* codegen_init ****************************************************************
94
95    TODO
96
97 *******************************************************************************/
98
99 void codegen_init()
100 {
101 #if defined(__I386__) || defined(__X86_64__)
102         /* this tree is global, not method specific */
103         if (!methodtree) {
104                 methodtree_element *mte;
105
106                 methodtree = avl_create(methodtree_comparator, NULL, NULL);
107
108                 /* insert asm_calljavafunction */
109
110                 mte = NEW(methodtree_element);
111
112                 mte->startpc = (functionptr) asm_calljavafunction;
113                 mte->endpc = (functionptr) ((ptrint) asm_calljavafunction2 - 1);
114
115                 avl_insert(methodtree, mte);
116
117                 /* insert asm_calljavafunction2 */
118
119                 mte = NEW(methodtree_element);
120
121                 mte->startpc = (functionptr) asm_calljavafunction2;
122                 mte->endpc = (functionptr) ((ptrint) asm_call_jit_compiler - 1);
123
124                 avl_insert(methodtree, mte);
125         }
126 #endif
127 }
128
129
130 /* codegen_setup **************************************************************
131
132    allocates and initialises code area, data area and references
133
134 *******************************************************************************/
135
136 void codegen_setup(methodinfo *m, codegendata *cd, t_inlining_globals *id)
137 {
138         cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
139         cd->mcodesize = MCODEINITSIZE;
140         
141         cd->dsegtop = DMNEW(u1, DSEGINITSIZE);
142         cd->dsegsize = DSEGINITSIZE;
143         cd->dsegtop += cd->dsegsize;
144         cd->dseglen = 0;
145
146         cd->jumpreferences = NULL;
147         cd->datareferences = NULL;
148         cd->xboundrefs = NULL;
149         cd->xcheckarefs = NULL;
150         cd->xnullrefs = NULL;
151         cd->xcastrefs = NULL;
152         cd->xdivrefs = NULL;
153         cd->xexceptionrefs = NULL;
154         cd->patchrefs = NULL;
155
156         cd->linenumberreferences = NULL;
157         cd->linenumbertablesizepos = 0;
158         cd->linenumbertablestartpos = 0;
159         cd->linenumbertab = 0;
160         
161         cd->method = m;
162         cd->exceptiontable = 0;
163         cd->exceptiontablelength = 0;
164
165         if (useinlining && id) {
166                 if (id->cumextablelength > 0) {
167                         cd->exceptiontablelength = id->cumextablelength;
168                         cd->exceptiontable =
169                                 DMNEW(exceptiontable, id->cumextablelength + 1);
170                 }
171
172         } else if (id && (id->method->exceptiontablelength > 0)) {
173                 cd->exceptiontablelength = m->exceptiontablelength;
174                 cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
175         }
176
177         if (id) {
178                 cd->maxstack = id->cummaxstack;
179                 cd->maxlocals = id->cumlocals;
180         } else {
181                 cd->maxstack = m->maxstack;
182                 cd->maxlocals = m->maxlocals;
183         }
184
185 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
186         cd->threadcritcurrent.next = NULL;
187         cd->threadcritcount = 0;
188 #endif
189 }
190
191
192 /* codegen_free ****************************************************************
193
194    Releases temporary code and data area.
195
196 *******************************************************************************/
197
198 void codegen_free(methodinfo *m, codegendata *cd)
199 {
200 #if 0
201         if (cd) {
202                 if (cd->mcodebase) {
203                         MFREE(cd->mcodebase, u1, cd->mcodesize);
204                         cd->mcodebase = NULL;
205                 }
206
207                 if (cd->dsegtop) {
208                         MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
209                         cd->dsegtop = NULL;
210                 }
211         }
212 #endif
213 }
214
215
216 /* codegen_close ***************************************************************
217
218    TODO
219
220 *******************************************************************************/
221
222 void codegen_close()
223 {
224         /* TODO: release avl tree on i386 and x86_64 */
225 }
226
227
228 /* codegen_increase doubles code area                                         */
229
230 static s4 *codegen_increase(codegendata *cd, u1 *codeptr)
231 {
232         long len;
233
234         len = codeptr - cd->mcodebase;
235         cd->mcodebase = DMREALLOC(cd->mcodebase,
236                                                           u1,
237                                                           cd->mcodesize,
238                                                           cd->mcodesize * 2);
239         cd->mcodesize *= 2;
240         cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
241
242         return (s4 *) (cd->mcodebase + len);
243 }
244
245
246 /* desg_increase doubles data area                                            */
247
248 static void dseg_increase(codegendata *cd)
249 {
250         u1 *newstorage;
251
252         newstorage = DMNEW(u1, cd->dsegsize * 2);
253
254         memcpy(newstorage + cd->dsegsize, cd->dsegtop - cd->dsegsize, cd->dsegsize);
255 #if 0
256         MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
257 #endif
258
259         cd->dsegtop = newstorage;
260         cd->dsegsize *= 2;
261         cd->dsegtop += cd->dsegsize;
262 }
263
264
265 static s4 dseg_adds4_increase(codegendata *cd, s4 value)
266 {
267         dseg_increase(cd);
268
269         *((s4 *) (cd->dsegtop - cd->dseglen)) = value;
270
271         return -(cd->dseglen);
272 }
273
274
275 static s4 dseg_adds4(codegendata *cd, s4 value)
276 {
277         s4 *dataptr;
278
279         cd->dseglen += 4;
280         dataptr = (s4 *) (cd->dsegtop - cd->dseglen);
281
282         if (cd->dseglen > cd->dsegsize)
283                 return dseg_adds4_increase(cd, value);
284
285         *dataptr = value;
286
287         return -(cd->dseglen);
288 }
289
290
291 #if !defined(__I386__) && !defined(__POWERPC__)
292 static s4 dseg_adds8_increase(codegendata *cd, s8 value)
293 {
294         dseg_increase(cd);
295
296         *((s8 *) (cd->dsegtop - cd->dseglen)) = value;
297
298         return -(cd->dseglen);
299 }
300
301
302 static s4 dseg_adds8(codegendata *cd, s8 value)
303 {
304         s8 *dataptr;
305
306         cd->dseglen = ALIGN(cd->dseglen + 8, 8);
307         dataptr = (s8 *) (cd->dsegtop - cd->dseglen);
308
309         if (cd->dseglen > cd->dsegsize)
310                 return dseg_adds8_increase(cd, value);
311
312         *dataptr = value;
313
314         return -(cd->dseglen);
315 }
316 #endif
317
318
319 #if !defined(__XDSPCORE__)
320 static s4 dseg_addfloat_increase(codegendata *cd, float value)
321 {
322         dseg_increase(cd);
323
324         *((float *) (cd->dsegtop - cd->dseglen)) = value;
325
326         return -(cd->dseglen);
327 }
328
329
330 static s4 dseg_addfloat(codegendata *cd, float value)
331 {
332         float *dataptr;
333
334         cd->dseglen += 4;
335         dataptr = (float *) (cd->dsegtop - cd->dseglen);
336
337         if (cd->dseglen > cd->dsegsize)
338                 return dseg_addfloat_increase(cd, value);
339
340         *dataptr = value;
341
342         return -(cd->dseglen);
343 }
344
345
346 static s4 dseg_adddouble_increase(codegendata *cd, double value)
347 {
348         dseg_increase(cd);
349
350         *((double *) (cd->dsegtop - cd->dseglen)) = value;
351
352         return -(cd->dseglen);
353 }
354
355
356 static s4 dseg_adddouble(codegendata *cd, double value)
357 {
358         double *dataptr;
359
360         cd->dseglen = ALIGN(cd->dseglen + 8, 8);
361         dataptr = (double *) (cd->dsegtop - cd->dseglen);
362
363         if (cd->dseglen > cd->dsegsize)
364                 return dseg_adddouble_increase(cd, value);
365
366         *dataptr = value;
367
368         return -(cd->dseglen);
369 }
370 #endif /* !defined(__XDSPCORE__) */
371
372
373 static void dseg_addtarget(codegendata *cd, basicblock *target)
374 {
375         jumpref *jr;
376
377         jr = DNEW(jumpref);
378         jr->tablepos = dseg_addaddress(cd, NULL);
379         jr->target = target;
380         jr->next = cd->jumpreferences;
381         cd->jumpreferences = jr;
382 }
383
384
385 #if defined(__I386__) || defined(__X86_64__)
386 static void dseg_adddata(codegendata *cd, u1 *ptr)
387 {
388         dataref *dr;
389
390         dr = DNEW(dataref);
391         dr->pos = (u1 *) (ptr - cd->mcodebase);
392         dr->next = cd->datareferences;
393         cd->datareferences = dr;
394 }
395 #endif
396
397
398 static void dseg_addlinenumbertablesize(codegendata *cd)
399 {
400 #if defined (__ALPHA__) || defined (__X86_64__)
401         dseg_adds4(cd, 0); /*PADDING*/
402 #endif
403         cd->linenumbertablesizepos = dseg_addaddress(cd, NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
404
405         cd->linenumbertablestartpos = dseg_addaddress(cd, NULL);
406 #if defined(__ALPHA__) || defined (__X86_64__)
407         dseg_adds4(cd, 0); /*PADDING*/
408 #endif
409 }
410
411
412 static void dseg_addlinenumber(codegendata *cd, u2 linenumber, u1 *ptr)
413 {
414         linenumberref *lr;
415
416         lr = DNEW(linenumberref);
417         lr->linenumber = linenumber;
418         lr->tablepos = 0;
419         lr->targetmpc = (ptr - cd->mcodebase);
420         lr->next = cd->linenumberreferences;
421         cd->linenumberreferences = lr;
422 }
423
424
425 /* we need this function externally on i386 and x86_64, but keep the call fast
426    on alpha... */
427
428 #if defined(__I386__) || defined(__X86_64__)
429 void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
430 #else
431 static void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
432 #endif
433 {
434         s4 branchpos;
435
436         branchpos = (u1 *) branchptr - cd->mcodebase;
437
438         /* Check if the target basicblock has already a start pc, so the jump is  */
439         /* backward and we can resolve it immediately.                            */
440
441         if (target->mpc >= 0) {
442                 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
443                                                   branchpos,
444                                                   target->mpc);
445
446         } else {
447                 branchref *br = DNEW(branchref);
448
449                 br->branchpos = branchpos;
450                 br->next = target->branchrefs;
451                 target->branchrefs = br;
452         }
453 }
454
455
456 static void codegen_addxboundrefs(codegendata *cd, void *branchptr, s4 reg)
457 {
458         s4 branchpos;
459         branchref *br;
460
461         branchpos = (u1 *) branchptr - cd->mcodebase;
462
463         br = DNEW(branchref);
464         br->branchpos = branchpos;
465         br->reg = reg;
466         br->next = cd->xboundrefs;
467         cd->xboundrefs = br;
468 }
469
470
471 static void codegen_addxcheckarefs(codegendata *cd, void *branchptr)
472 {
473         s4 branchpos;
474         branchref *br;
475
476         branchpos = (u1 *) branchptr - cd->mcodebase;
477
478         br = DNEW(branchref);
479         br->branchpos = branchpos;
480         br->next = cd->xcheckarefs;
481         cd->xcheckarefs = br;
482 }
483
484
485 static void codegen_addxnullrefs(codegendata *cd, void *branchptr)
486 {
487         s4 branchpos;
488         branchref *br;
489
490         branchpos = (u1 *) branchptr - cd->mcodebase;
491
492         br = DNEW(branchref);
493         br->branchpos = branchpos;
494         br->next = cd->xnullrefs;
495         cd->xnullrefs = br;
496 }
497
498
499 static void codegen_addxcastrefs(codegendata *cd, void *branchptr)
500 {
501         s4 branchpos;
502         branchref *br;
503
504         branchpos = (u1 *) branchptr - cd->mcodebase;
505
506         br = DNEW(branchref);
507         br->branchpos = branchpos;
508         br->next = cd->xcastrefs;
509         cd->xcastrefs = br;
510 }
511
512
513 static void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
514 {
515         s4 branchpos;
516         branchref *br;
517
518         branchpos = (u1 *) branchptr - cd->mcodebase;
519
520         br = DNEW(branchref);
521         br->branchpos = branchpos;
522         br->next = cd->xexceptionrefs;
523         cd->xexceptionrefs = br;
524 }
525
526
527 #if defined(__I386__) || defined(__X86_64__)
528 static void codegen_addxdivrefs(codegendata *cd, void *branchptr)
529 {
530         s4 branchpos;
531         branchref *br;
532
533         branchpos = (u1 *) branchptr - cd->mcodebase;
534
535         br = DNEW(branchref);
536         br->branchpos = branchpos;
537         br->next = cd->xdivrefs;
538         cd->xdivrefs = br;
539 }
540 #endif
541
542
543 static void codegen_addpatchref(codegendata *cd,
544                                                                 voidptr branchptr,
545                                                                 functionptr patcher,
546                                                                 voidptr ref)
547 {
548         patchref *pr;
549         s4        branchpos;
550
551         branchpos = (u1 *) branchptr - cd->mcodebase;
552
553         pr = DNEW(patchref);
554         pr->branchpos = branchpos;
555         pr->patcher = patcher;
556         pr->ref = ref;
557         pr->next = cd->patchrefs;
558         cd->patchrefs = pr;
559 }
560
561
562 static void codegen_createlinenumbertable(codegendata *cd)
563 {
564 #if defined(__I386__) || defined(__ALPHA__) || defined(__X86_64__)
565         linenumberref *lr;
566
567         for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
568                 lr->tablepos = dseg_addaddress(cd, NULL);
569
570                 if (cd->linenumbertab == 0)
571                         cd->linenumbertab = lr->tablepos;
572
573                 dseg_addaddress(cd, lr->linenumber);
574         }
575 #endif
576 }
577
578
579 #if defined(__I386__) || defined(__X86_64__)
580 static int methodtree_comparator(const void *pc, const void *element, void *param)
581 {
582         methodtree_element *mte;
583         methodtree_element *mtepc;
584
585         mte = (methodtree_element *) element;
586         mtepc = (methodtree_element *) pc;
587
588         /* compare both startpc and endpc of pc, even if they have the same value,
589            otherwise the avl_probe sometimes thinks the element is already in the
590            tree */
591         if ((long) mte->startpc <= (long) mtepc->startpc &&
592                 (long) mtepc->startpc <= (long) mte->endpc &&
593                 (long) mte->startpc <= (long) mtepc->endpc &&
594                 (long) mtepc->endpc <= (long) mte->endpc) {
595                 return 0;
596
597         } else if ((long) mtepc->startpc < (long) mte->startpc) {
598                 return -1;
599
600         } else {
601                 return 1;
602         }
603 }
604
605
606 void codegen_insertmethod(functionptr startpc, functionptr endpc)
607 {
608         methodtree_element *mte;
609
610 #if defined(USE_THREADS)
611 #if defined(NATIVE_THREADS)
612         tables_lock();
613 #endif
614 #endif
615
616         mte = NEW(methodtree_element);
617         mte->startpc = startpc;
618         mte->endpc = endpc;
619
620         if (avl_insert(methodtree, mte)) {
621 #if defined(USE_THREADS)
622 #if defined(NATIVE_THREADS)
623                 tables_unlock();
624 #endif
625 #endif
626                 assert(0);
627                 throw_cacao_exception_exit(string_java_lang_InternalError,
628                                                                    "duplicate entry");
629         }
630
631 #if defined(USE_THREADS)
632 #if defined(NATIVE_THREADS)
633         tables_unlock();
634 #endif
635 #endif
636 }
637
638
639 functionptr codegen_findmethod(functionptr pc)
640 {
641         methodtree_element *mtepc;
642         methodtree_element *mte;
643
644 #if defined(USE_THREADS)
645 #if defined(NATIVE_THREADS)
646         tables_lock();
647 #endif
648 #endif
649
650         mtepc = NEW(methodtree_element);
651         mtepc->startpc = pc;
652         mtepc->endpc = pc;
653
654         mte = avl_find(methodtree, mtepc);
655
656         FREE(mtepc, methodtree_element);
657
658         if (!mte) {
659 #if defined(USE_THREADS)
660 #if defined(NATIVE_THREADS)
661                 tables_unlock();
662 #endif
663 #endif
664 #ifdef JWDEBUG_X86
665                         {
666                                 void *bt[5];
667                                 fprintf(stderr,"backtrace:");
668                                 backtrace_symbols_fd(bt,5,2);
669                         }
670 #endif
671                 assert(0);
672                 throw_cacao_exception_exit(string_java_lang_InternalError,
673                                                                    "Cannot find Java function at %p", pc);
674         }
675
676 #if defined(USE_THREADS)
677 #if defined(NATIVE_THREADS)
678         tables_unlock();
679 #endif
680 #endif
681
682         return mte->startpc;
683 }
684 #endif
685
686 #if defined(__ALPHA__)
687 /*perhaps in the end I'll have to go for the tree version on alpha too, since this is insecure for eg segfault signals in native code,
688 since it will still return an adress of a datasegment, but which will not be a valid one of a java method. This version is faster though (jowenn)*/
689 void *codegen_findmethod(void *returnAdress)
690  {
691         void *result;
692         s8 d;
693         void *dataseg;
694         d=*((s4*)returnAdress);
695         d=d<<48;
696         d=d>>48;
697         dataseg=returnAdress+d;
698         d=*(((s4*)returnAdress)+1);
699         d=d>>16;
700         d=d-0x177b;
701         if (d==0) {
702                 d=*(((s4*)returnAdress)+1);
703                 d=d<<16;
704                 dataseg=dataseg+d;
705         }
706         return dataseg;
707 #if 0
708         ldl     t0,0(ra)              /* load instruction LDA PV,xxx(RA)          */
709         sll     t0,48,t0
710         sra     t0,48,t0              /* isolate offset                           */
711         addq    t0,ra,pv              /* compute update address                   */
712         ldl     t0,4(ra)              /* load instruction LDAH PV,xxx(PV)         */
713         srl     t0,16,t0              /* isolate instruction code                 */
714         lda     t0,-0x177b(t0)        /* test for LDAH                            */
715         bne     t0,ex_stack_loop
716         ldl     t0,4(ra)              /* load instruction LDAH PV,xxx(RA)         */
717         sll     t0,16,t0              /* compute high offset                      */
718         addl    t0,0,t0               /* sign extend high offset                  */
719         addq    t0,pv,pv              /* compute update address                   */
720         br      ex_stack_loop
721 #endif
722 }
723
724 #endif
725
726
727 /* codegen_finish **************************************************************
728
729    Finishes the code generation. A new memory, large enough for both
730    data and code, is allocated and data and code are copied together
731    to their final layout, unresolved jumps are resolved, ...
732
733 *******************************************************************************/
734
735 static void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
736 {
737         jumpref     *jr;
738         functionptr  epoint;
739         s4           extralen;
740         s4           alignedlen;
741
742 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
743         extralen = sizeof(threadcritnode) * cd->threadcritcount;
744 #else
745         extralen = 0;
746 #endif
747
748 #if defined(STATISTICS)
749         if (opt_stat) {
750                 count_code_len += mcodelen;
751                 count_data_len += cd->dseglen;
752         }
753 #endif
754
755         cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
756         alignedlen = ALIGN(mcodelen, MAX_ALIGN) + cd->dseglen;
757
758         /* allocate new memory */
759
760         m->mcodelength = mcodelen + cd->dseglen;
761         m->mcode = (functionptr) (ptrint) CNEW(u1, alignedlen + extralen);
762
763         /* copy data and code to their new location */
764
765         MCOPY((void *) (ptrint) m->mcode, cd->dsegtop - cd->dseglen, u1,
766                   cd->dseglen);
767         MCOPY((void *) ((ptrint) m->mcode + cd->dseglen), cd->mcodebase, u1,
768                   mcodelen);
769
770         m->entrypoint = epoint = (functionptr) ((ptrint) m->mcode + cd->dseglen);
771
772         /* jump table resolving */
773
774         jr = cd->jumpreferences;
775         while (jr != NULL) {
776                 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
777                         (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
778                 jr = jr->next;
779         }
780
781 #if defined(__I386__) || defined(__ALPHA__) || defined(__X86_64__)
782         /* line number table resolving */
783         {
784                 linenumberref *lr;
785                 ptrint lrtlen = 0;
786
787                 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
788                         lrtlen++;
789                         *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
790                                 (functionptr) ((ptrint) epoint + (ptrint) lr->targetmpc);
791                 }
792                 
793                 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
794                         (functionptr) ((ptrint) epoint + cd->linenumbertab);
795
796                 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
797         }
798 #endif
799
800 #if defined(__I386__) || defined(__X86_64__)
801         /* add method into methodtree to find the entrypoint */
802
803         codegen_insertmethod(m->entrypoint,
804                                                  (functionptr) ((ptrint) m->entrypoint + mcodelen));
805 #endif
806
807 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__)
808         {
809                 dataref *dr;
810
811                 /* data segment references resolving */
812
813                 dr = cd->datareferences;
814                 while (dr != NULL) {
815                         *((functionptr *) ((ptrint) epoint + (ptrint) dr->pos -
816                                                            SIZEOF_VOID_P)) = epoint;
817                         dr = dr->next;
818                 }
819         }
820 #endif
821
822 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
823         {
824                 threadcritnode *n = (threadcritnode *) ((ptrint) m->mcode + alignedlen);
825                 s4 i;
826                 threadcritnodetemp *nt = cd->threadcrit;
827
828                 for (i = 0; i < cd->threadcritcount; i++) {
829                         n->mcodebegin = (u1 *) (ptrint) m->mcode + nt->mcodebegin;
830                         n->mcodeend = (u1 *) (ptrint) m->mcode + nt->mcodeend;
831                         n->mcoderestart = (u1 *) (ptrint) m->mcode + nt->mcoderestart;
832                         thread_registercritical(n);
833                         n++;
834                         nt = nt->next;
835                 }
836         }
837 #endif
838 }
839
840
841 void dseg_display(methodinfo *m, codegendata *cd)
842 {
843         s4 *s4ptr;
844         s4 i;
845         
846         s4ptr = (s4 *) (ptrint) m->mcode;
847
848         printf("  --- dump of datasegment\n");
849         for (i = cd->dseglen; i > 0 ; i -= 4) {
850 #if SIZEOF_VOID_P == 8
851                 printf("0x%016lx:   -%6x (%6d): %8x\n",
852                            (ptrint) s4ptr, i, i, (s4) *s4ptr);
853 #else
854                 printf("0x%08x:   -%6x (%6d): %8x\n",
855                            (ptrint) s4ptr, i, i, (s4) *s4ptr);
856 #endif
857                 s4ptr++;
858         }
859
860         printf("  --- begin of data segment: %p\n", (void *) s4ptr);
861 }
862
863
864
865 /* codegen_createnativestub ****************************************************
866
867    Wrapper for createnativestub.
868
869 *******************************************************************************/
870
871 functionptr codegen_createnativestub(functionptr f, methodinfo *m)
872 {
873         codegendata        *cd;
874         registerdata       *rd;
875         t_inlining_globals *id;
876         s4                  dumpsize;
877
878         /* mark dump memory */
879
880         dumpsize = dump_size();
881
882         cd = DNEW(codegendata);
883         rd = DNEW(registerdata);
884         id = DNEW(t_inlining_globals);
885
886         /* setup code generation stuff */
887
888         inlining_setup(m, id);
889         reg_setup(m, rd, id);
890         codegen_setup(m, cd, id);
891                                                 
892         m->stubroutine = createnativestub(f, m, cd, rd);
893
894         /* entrypoint was set in codegen_finish, clear it */
895
896         m->entrypoint = NULL;
897
898 #if defined(STATISTICS)
899         if (opt_stat)
900                 count_nstub_len += m->mcodelength + cd->dseglen;
901 #endif
902
903         /* release memory */
904
905         dump_release(dumpsize);
906
907
908         /* disassemble native stub */
909
910         if (showdisassemble)
911                 codegen_disassemble_nativestub(m, (s4 *) (ptrint) m->stubroutine,
912                                                                            m->mcodelength);
913
914         /* return stubroutine entry point */
915
916         return m->stubroutine;
917 }
918
919
920 /* codegen_disassemble_nativestub **********************************************
921
922    Disassembles the generated native stub.
923
924 *******************************************************************************/
925
926 void codegen_disassemble_nativestub(methodinfo *m, s4 *code, s4 len)
927 {
928         printf("Native stub: ");
929         utf_fprint_classname(stdout, m->class->name);
930         printf(".");
931         utf_fprint(stdout, m->name);
932         utf_fprint(stdout, m->descriptor);
933         printf("\n\nLength: %d\n\n", len);
934
935 #if defined(__I386__) || defined(__X86_64__)
936         disassemble((u1 *) code, len);
937 #else
938         disassemble(code, len);
939 #endif
940 }
941
942
943 /* removecompilerstub **********************************************************
944
945    Deletes a compilerstub from memory (simply by freeing it).
946
947 *******************************************************************************/
948
949 void removecompilerstub(functionptr stub)
950 {
951         CFREE(stub, 1);
952 }
953
954
955 /* removenativestub ************************************************************
956
957    Removes a previously created native-stub from memory.
958     
959 *******************************************************************************/
960
961 void removenativestub(functionptr stub)
962 {
963         CFREE(stub, 1);
964 }
965
966
967 /* reg_of_var:
968     This function determines a register, to which the result of an operation
969     should go, when it is ultimatively intended to store the result in
970     pseudoregister v.
971     If v is assigned to an actual register, this register will be returned.
972     Otherwise (when v is spilled) this function returns tempregnum.
973     If not already done, regoff and flags are set in the stack location.
974 */        
975
976 static int reg_of_var(registerdata *rd, stackptr v, int tempregnum)
977 {
978         varinfo *var;
979
980         switch (v->varkind) {
981         case TEMPVAR:
982                 if (!(v->flags & INMEMORY))
983                         return(v->regoff);
984                 break;
985
986         case STACKVAR:
987                 var = &(rd->interfaces[v->varnum][v->type]);
988                 v->regoff = var->regoff;
989                 if (!(var->flags & INMEMORY))
990                         return(var->regoff);
991                 break;
992
993         case LOCALVAR:
994                 var = &(rd->locals[v->varnum][v->type]);
995                 v->regoff = var->regoff;
996                 if (!(var->flags & INMEMORY))
997                         return(var->regoff);
998                 break;
999
1000         case ARGVAR:
1001                 if (!(v->flags & INMEMORY))
1002                         return(v->regoff);
1003                 break;
1004         }
1005 #ifdef STATISTICS
1006         if (opt_stat)
1007                 count_spills_read++;
1008 #endif
1009         v->flags |= INMEMORY;
1010         return tempregnum;
1011 }
1012
1013
1014 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1015 static void codegen_threadcritrestart(codegendata *cd, int offset)
1016 {
1017         cd->threadcritcurrent.mcoderestart = offset;
1018 }
1019
1020
1021 static void codegen_threadcritstart(codegendata *cd, int offset)
1022 {
1023         cd->threadcritcurrent.mcodebegin = offset;
1024 }
1025
1026
1027 static void codegen_threadcritstop(codegendata *cd, int offset)
1028 {
1029         cd->threadcritcurrent.next = cd->threadcrit;
1030         cd->threadcritcurrent.mcodeend = offset;
1031         cd->threadcrit = DNEW(threadcritnodetemp);
1032         *(cd->threadcrit) = cd->threadcritcurrent;
1033         cd->threadcritcount++;
1034 }
1035 #endif
1036
1037
1038 /*
1039  * These are local overrides for various environment variables in Emacs.
1040  * Please do not remove this and leave it at the end of the file, where
1041  * Emacs will automagically detect them.
1042  * ---------------------------------------------------------------------
1043  * Local variables:
1044  * mode: c
1045  * indent-tabs-mode: t
1046  * c-basic-offset: 4
1047  * tab-width: 4
1048  * End:
1049  */