c97de8303a733e790b9249ea782b381e09d8ca90
[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 2661 2005-06-13 14:17:37Z 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__)
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 static void dseg_adddata(codegendata *cd, u1 *ptr)
386 {
387         dataref *dr;
388
389         dr = DNEW(dataref);
390         dr->pos = (u1 *) (ptr - cd->mcodebase);
391         dr->next = cd->datareferences;
392         cd->datareferences = dr;
393 }
394
395
396 static void dseg_addlinenumbertablesize(codegendata *cd)
397 {
398 #if defined (__ALPHA__) || defined (__X86_64__)
399         dseg_adds4(cd, 0); /*PADDING*/
400 #endif
401         cd->linenumbertablesizepos = dseg_addaddress(cd, NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
402
403         cd->linenumbertablestartpos = dseg_addaddress(cd, NULL);
404 #if defined(__ALPHA__) || defined (__X86_64__)
405         dseg_adds4(cd, 0); /*PADDING*/
406 #endif
407 }
408
409
410 static void dseg_addlinenumber(codegendata *cd, u2 linenumber, u1 *ptr)
411 {
412         linenumberref *lr;
413
414         lr = DNEW(linenumberref);
415         lr->linenumber = linenumber;
416         lr->tablepos = 0;
417         lr->targetmpc = (ptr - cd->mcodebase);
418         lr->next = cd->linenumberreferences;
419         cd->linenumberreferences = lr;
420 }
421
422
423 /* we need this function externally on i386 and x86_64, but keep the call fast
424    on alpha... */
425
426 #if defined(__I386__) || defined(__X86_64__)
427 void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
428 #else
429 static void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
430 #endif
431 {
432         s4 branchpos;
433
434         branchpos = (u1 *) branchptr - cd->mcodebase;
435
436         /* Check if the target basicblock has already a start pc, so the jump is  */
437         /* backward and we can resolve it immediately.                            */
438
439         if (target->mpc >= 0) {
440                 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
441                                                   branchpos,
442                                                   target->mpc);
443
444         } else {
445                 branchref *br = DNEW(branchref);
446
447                 br->branchpos = branchpos;
448                 br->next = target->branchrefs;
449                 target->branchrefs = br;
450         }
451 }
452
453
454 static void codegen_addxboundrefs(codegendata *cd, void *branchptr, s4 reg)
455 {
456         s4 branchpos;
457         branchref *br;
458
459         branchpos = (u1 *) branchptr - cd->mcodebase;
460
461         br = DNEW(branchref);
462         br->branchpos = branchpos;
463         br->reg = reg;
464         br->next = cd->xboundrefs;
465         cd->xboundrefs = br;
466 }
467
468
469 static void codegen_addxcheckarefs(codegendata *cd, void *branchptr)
470 {
471         s4 branchpos;
472         branchref *br;
473
474         branchpos = (u1 *) branchptr - cd->mcodebase;
475
476         br = DNEW(branchref);
477         br->branchpos = branchpos;
478         br->next = cd->xcheckarefs;
479         cd->xcheckarefs = br;
480 }
481
482
483 static void codegen_addxnullrefs(codegendata *cd, void *branchptr)
484 {
485         s4 branchpos;
486         branchref *br;
487
488         branchpos = (u1 *) branchptr - cd->mcodebase;
489
490         br = DNEW(branchref);
491         br->branchpos = branchpos;
492         br->next = cd->xnullrefs;
493         cd->xnullrefs = br;
494 }
495
496
497 static void codegen_addxcastrefs(codegendata *cd, void *branchptr)
498 {
499         s4 branchpos;
500         branchref *br;
501
502         branchpos = (u1 *) branchptr - cd->mcodebase;
503
504         br = DNEW(branchref);
505         br->branchpos = branchpos;
506         br->next = cd->xcastrefs;
507         cd->xcastrefs = br;
508 }
509
510
511 static void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
512 {
513         s4 branchpos;
514         branchref *br;
515
516         branchpos = (u1 *) branchptr - cd->mcodebase;
517
518         br = DNEW(branchref);
519         br->branchpos = branchpos;
520         br->next = cd->xexceptionrefs;
521         cd->xexceptionrefs = br;
522 }
523
524
525 #if defined(__I386__) || defined(__X86_64__)
526 static void codegen_addxdivrefs(codegendata *cd, void *branchptr)
527 {
528         s4 branchpos;
529         branchref *br;
530
531         branchpos = (u1 *) branchptr - cd->mcodebase;
532
533         br = DNEW(branchref);
534         br->branchpos = branchpos;
535         br->next = cd->xdivrefs;
536         cd->xdivrefs = br;
537 }
538 #endif
539
540
541 static void codegen_addpatchref(codegendata *cd,
542                                                                 voidptr branchptr,
543                                                                 functionptr patcher,
544                                                                 voidptr ref)
545 {
546         patchref *pr;
547         s4        branchpos;
548
549         branchpos = (u1 *) branchptr - cd->mcodebase;
550
551         pr = DNEW(patchref);
552         pr->branchpos = branchpos;
553         pr->patcher = patcher;
554         pr->ref = ref;
555         pr->next = cd->patchrefs;
556         cd->patchrefs = pr;
557 }
558
559
560 static void codegen_createlinenumbertable(codegendata *cd)
561 {
562 #if defined(__I386__) || defined(__ALPHA__) || defined(__X86_64__)
563         linenumberref *lr;
564
565         for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
566                 lr->tablepos = dseg_addaddress(cd, NULL);
567
568                 if (cd->linenumbertab == 0)
569                         cd->linenumbertab = lr->tablepos;
570
571                 dseg_addaddress(cd, lr->linenumber);
572         }
573 #endif
574 }
575
576
577 #if defined(__I386__) || defined(__X86_64__)
578 static int methodtree_comparator(const void *pc, const void *element, void *param)
579 {
580         methodtree_element *mte;
581         methodtree_element *mtepc;
582
583         mte = (methodtree_element *) element;
584         mtepc = (methodtree_element *) pc;
585
586         /* compare both startpc and endpc of pc, even if they have the same value,
587            otherwise the avl_probe sometimes thinks the element is already in the
588            tree */
589         if ((long) mte->startpc <= (long) mtepc->startpc &&
590                 (long) mtepc->startpc <= (long) mte->endpc &&
591                 (long) mte->startpc <= (long) mtepc->endpc &&
592                 (long) mtepc->endpc <= (long) mte->endpc) {
593                 return 0;
594
595         } else if ((long) mtepc->startpc < (long) mte->startpc) {
596                 return -1;
597
598         } else {
599                 return 1;
600         }
601 }
602
603
604 void codegen_insertmethod(functionptr startpc, functionptr endpc)
605 {
606         methodtree_element *mte;
607
608 #if defined(USE_THREADS)
609 #if defined(NATIVE_THREADS)
610         tables_lock();
611 #endif
612 #endif
613
614         mte = NEW(methodtree_element);
615         mte->startpc = startpc;
616         mte->endpc = endpc;
617
618         if (avl_insert(methodtree, mte)) {
619 #if defined(USE_THREADS)
620 #if defined(NATIVE_THREADS)
621                 tables_unlock();
622 #endif
623 #endif
624                 assert(0);
625                 throw_cacao_exception_exit(string_java_lang_InternalError,
626                                                                    "duplicate entry");
627         }
628
629 #if defined(USE_THREADS)
630 #if defined(NATIVE_THREADS)
631         tables_unlock();
632 #endif
633 #endif
634 }
635
636
637 functionptr codegen_findmethod(functionptr pc)
638 {
639         methodtree_element *mtepc;
640         methodtree_element *mte;
641
642 #if defined(USE_THREADS)
643 #if defined(NATIVE_THREADS)
644         tables_lock();
645 #endif
646 #endif
647
648         mtepc = NEW(methodtree_element);
649         mtepc->startpc = pc;
650         mtepc->endpc = pc;
651
652         mte = avl_find(methodtree, mtepc);
653
654         FREE(mtepc, methodtree_element);
655
656         if (!mte) {
657 #if defined(USE_THREADS)
658 #if defined(NATIVE_THREADS)
659                 tables_unlock();
660 #endif
661 #endif
662 #ifdef JWDEBUG_X86
663                         {
664                                 void *bt[5];
665                                 fprintf(stderr,"backtrace:");
666                                 backtrace_symbols_fd(bt,5,2);
667                         }
668 #endif
669                 assert(0);
670                 throw_cacao_exception_exit(string_java_lang_InternalError,
671                                                                    "Cannot find Java function at %p", pc);
672         }
673
674 #if defined(USE_THREADS)
675 #if defined(NATIVE_THREADS)
676         tables_unlock();
677 #endif
678 #endif
679
680         return mte->startpc;
681 }
682 #endif
683
684 #if defined(__ALPHA__)
685 /*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,
686 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)*/
687 void *codegen_findmethod(void *returnAdress)
688  {
689         void *result;
690         s8 d;
691         void *dataseg;
692         d=*((s4*)returnAdress);
693         d=d<<48;
694         d=d>>48;
695         dataseg=returnAdress+d;
696         d=*(((s4*)returnAdress)+1);
697         d=d>>16;
698         d=d-0x177b;
699         if (d==0) {
700                 d=*(((s4*)returnAdress)+1);
701                 d=d<<16;
702                 dataseg=dataseg+d;
703         }
704         return dataseg;
705 #if 0
706         ldl     t0,0(ra)              /* load instruction LDA PV,xxx(RA)          */
707         sll     t0,48,t0
708         sra     t0,48,t0              /* isolate offset                           */
709         addq    t0,ra,pv              /* compute update address                   */
710         ldl     t0,4(ra)              /* load instruction LDAH PV,xxx(PV)         */
711         srl     t0,16,t0              /* isolate instruction code                 */
712         lda     t0,-0x177b(t0)        /* test for LDAH                            */
713         bne     t0,ex_stack_loop
714         ldl     t0,4(ra)              /* load instruction LDAH PV,xxx(RA)         */
715         sll     t0,16,t0              /* compute high offset                      */
716         addl    t0,0,t0               /* sign extend high offset                  */
717         addq    t0,pv,pv              /* compute update address                   */
718         br      ex_stack_loop
719 #endif
720 }
721
722 #endif
723
724
725 /* codegen_finish **************************************************************
726
727    Finishes the code generation. A new memory, large enough for both
728    data and code, is allocated and data and code are copied together
729    to their final layout, unresolved jumps are resolved, ...
730
731 *******************************************************************************/
732
733 static void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
734 {
735         jumpref     *jr;
736         functionptr  epoint;
737         s4           extralen;
738         s4           alignedlen;
739
740 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
741         extralen = sizeof(threadcritnode) * cd->threadcritcount;
742 #else
743         extralen = 0;
744 #endif
745
746 #if defined(STATISTICS)
747         if (opt_stat) {
748                 count_code_len += mcodelen;
749                 count_data_len += cd->dseglen;
750         }
751 #endif
752
753         cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
754         alignedlen = ALIGN(mcodelen, MAX_ALIGN) + cd->dseglen;
755
756         /* allocate new memory */
757
758         m->mcodelength = mcodelen + cd->dseglen;
759         m->mcode = (functionptr) (ptrint) CNEW(u1, alignedlen + extralen);
760
761         /* copy data and code to their new location */
762
763         MCOPY((void *) (ptrint) m->mcode, cd->dsegtop - cd->dseglen, u1,
764                   cd->dseglen);
765         MCOPY((void *) ((ptrint) m->mcode + cd->dseglen), cd->mcodebase, u1,
766                   mcodelen);
767
768         m->entrypoint = epoint = (functionptr) ((ptrint) m->mcode + cd->dseglen);
769
770         /* jump table resolving */
771
772         jr = cd->jumpreferences;
773         while (jr != NULL) {
774                 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
775                         (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
776                 jr = jr->next;
777         }
778
779 #if defined(__I386__) || defined(__ALPHA__) || defined(__X86_64__)
780         /* line number table resolving */
781         {
782                 linenumberref *lr;
783                 ptrint lrtlen = 0;
784
785                 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
786                         lrtlen++;
787                         *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
788                                 (functionptr) ((ptrint) epoint + (ptrint) lr->targetmpc);
789                 }
790                 
791                 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
792                         (functionptr) ((ptrint) epoint + cd->linenumbertab);
793
794                 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
795         }
796 #endif
797
798 #if defined(__I386__) || defined(__X86_64__)
799         /* add method into methodtree to find the entrypoint */
800
801         codegen_insertmethod(m->entrypoint,
802                                                  (functionptr) ((ptrint) m->entrypoint + mcodelen));
803 #endif
804
805 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__)
806         {
807                 dataref *dr;
808
809                 /* data segment references resolving */
810
811                 dr = cd->datareferences;
812                 while (dr != NULL) {
813                         *((functionptr *) ((ptrint) epoint + (ptrint) dr->pos -
814                                                            SIZEOF_VOID_P)) = epoint;
815                         dr = dr->next;
816                 }
817         }
818 #endif
819
820 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
821         {
822                 threadcritnode *n = (threadcritnode *) ((ptrint) m->mcode + alignedlen);
823                 s4 i;
824                 threadcritnodetemp *nt = cd->threadcrit;
825
826                 for (i = 0; i < cd->threadcritcount; i++) {
827                         n->mcodebegin = (u1 *) (ptrint) m->mcode + nt->mcodebegin;
828                         n->mcodeend = (u1 *) (ptrint) m->mcode + nt->mcodeend;
829                         n->mcoderestart = (u1 *) (ptrint) m->mcode + nt->mcoderestart;
830                         thread_registercritical(n);
831                         n++;
832                         nt = nt->next;
833                 }
834         }
835 #endif
836 }
837
838
839 void dseg_display(methodinfo *m, codegendata *cd)
840 {
841         s4 *s4ptr;
842         s4 i;
843         
844         s4ptr = (s4 *) (ptrint) m->mcode;
845
846         printf("  --- dump of datasegment\n");
847         for (i = cd->dseglen; i > 0 ; i -= 4) {
848 #if SIZEOF_VOID_P == 8
849                 printf("0x%016lx:   -%6x (%6d): %8x\n",
850                            (ptrint) s4ptr, i, i, (s4) *s4ptr);
851 #else
852                 printf("0x%08x:   -%6x (%6d): %8x\n",
853                            (ptrint) s4ptr, i, i, (s4) *s4ptr);
854 #endif
855                 s4ptr++;
856         }
857
858         printf("  --- begin of data segment: %p\n", (void *) s4ptr);
859 }
860
861
862
863 /* codegen_createnativestub ****************************************************
864
865    Wrapper for createnativestub.
866
867 *******************************************************************************/
868
869 functionptr codegen_createnativestub(functionptr f, methodinfo *m)
870 {
871         codegendata        *cd;
872         registerdata       *rd;
873         t_inlining_globals *id;
874         s4                  dumpsize;
875
876         /* mark dump memory */
877
878         dumpsize = dump_size();
879
880         cd = DNEW(codegendata);
881         rd = DNEW(registerdata);
882         id = DNEW(t_inlining_globals);
883
884         /* setup code generation stuff */
885
886         inlining_setup(m, id);
887         reg_setup(m, rd, id);
888         codegen_setup(m, cd, id);
889                                                 
890         m->stubroutine = createnativestub(f, m, cd, rd);
891
892         /* entrypoint was set in codegen_finish, clear it */
893
894         m->entrypoint = NULL;
895
896 #if defined(STATISTICS)
897         if (opt_stat)
898                 count_nstub_len += m->mcodelength + cd->dseglen;
899 #endif
900
901         /* release memory */
902
903         dump_release(dumpsize);
904
905
906         /* disassemble native stub */
907
908         if (showdisassemble)
909                 codegen_disassemble_nativestub(m, (s4 *) (ptrint) m->stubroutine,
910                                                                            m->mcodelength);
911
912         /* return stubroutine entry point */
913
914         return m->stubroutine;
915 }
916
917
918 /* codegen_disassemble_nativestub **********************************************
919
920    Disassembles the generated native stub.
921
922 *******************************************************************************/
923
924 void codegen_disassemble_nativestub(methodinfo *m, s4 *code, s4 len)
925 {
926         printf("Native stub: ");
927         utf_fprint_classname(stdout, m->class->name);
928         printf(".");
929         utf_fprint(stdout, m->name);
930         utf_fprint(stdout, m->descriptor);
931         printf("\n\nLength: %d\n\n", len);
932
933 #if defined(__I386__) || defined(__X86_64__)
934         disassemble((u1 *) code, len);
935 #else
936         disassemble(code, len);
937 #endif
938 }
939
940
941 /* removecompilerstub **********************************************************
942
943    Deletes a compilerstub from memory (simply by freeing it).
944
945 *******************************************************************************/
946
947 void removecompilerstub(functionptr stub)
948 {
949         CFREE(stub, 1);
950 }
951
952
953 /* removenativestub ************************************************************
954
955    Removes a previously created native-stub from memory.
956     
957 *******************************************************************************/
958
959 void removenativestub(functionptr stub)
960 {
961         CFREE(stub, 1);
962 }
963
964
965 /* reg_of_var:
966     This function determines a register, to which the result of an operation
967     should go, when it is ultimatively intended to store the result in
968     pseudoregister v.
969     If v is assigned to an actual register, this register will be returned.
970     Otherwise (when v is spilled) this function returns tempregnum.
971     If not already done, regoff and flags are set in the stack location.
972 */        
973
974 static int reg_of_var(registerdata *rd, stackptr v, int tempregnum)
975 {
976         varinfo *var;
977
978         switch (v->varkind) {
979         case TEMPVAR:
980                 if (!(v->flags & INMEMORY))
981                         return(v->regoff);
982                 break;
983
984         case STACKVAR:
985                 var = &(rd->interfaces[v->varnum][v->type]);
986                 v->regoff = var->regoff;
987                 if (!(var->flags & INMEMORY))
988                         return(var->regoff);
989                 break;
990
991         case LOCALVAR:
992                 var = &(rd->locals[v->varnum][v->type]);
993                 v->regoff = var->regoff;
994                 if (!(var->flags & INMEMORY))
995                         return(var->regoff);
996                 break;
997
998         case ARGVAR:
999                 if (!(v->flags & INMEMORY))
1000                         return(v->regoff);
1001                 break;
1002         }
1003 #ifdef STATISTICS
1004         if (opt_stat)
1005                 count_spills_read++;
1006 #endif
1007         v->flags |= INMEMORY;
1008         return tempregnum;
1009 }
1010
1011
1012 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1013 static void codegen_threadcritrestart(codegendata *cd, int offset)
1014 {
1015         cd->threadcritcurrent.mcoderestart = offset;
1016 }
1017
1018
1019 static void codegen_threadcritstart(codegendata *cd, int offset)
1020 {
1021         cd->threadcritcurrent.mcodebegin = offset;
1022 }
1023
1024
1025 static void codegen_threadcritstop(codegendata *cd, int offset)
1026 {
1027         cd->threadcritcurrent.next = cd->threadcrit;
1028         cd->threadcritcurrent.mcodeend = offset;
1029         cd->threadcrit = DNEW(threadcritnodetemp);
1030         *(cd->threadcrit) = cd->threadcritcurrent;
1031         cd->threadcritcount++;
1032 }
1033 #endif
1034
1035
1036 /*
1037  * These are local overrides for various environment variables in Emacs.
1038  * Please do not remove this and leave it at the end of the file, where
1039  * Emacs will automagically detect them.
1040  * ---------------------------------------------------------------------
1041  * Local variables:
1042  * mode: c
1043  * indent-tabs-mode: t
1044  * c-basic-offset: 4
1045  * tab-width: 4
1046  * End:
1047  */