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