* lastmcodeptr: Stuff added.
[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 3474 2005-10-21 12:02:40Z twisti $
51
52 */
53
54
55 #include <assert.h>
56 #include <string.h>
57
58 #include "config.h"
59 #include "vm/types.h"
60
61 #include "mm/memory.h"
62 #include "toolbox/avl.h"
63 #include "toolbox/logging.h"
64 #include "native/jni.h"
65 #include "native/native.h"
66
67 #if defined(USE_THREADS)
68 # if defined(NATIVE_THREADS)
69 #  include "threads/native/threads.h"
70 # else
71 #  include "threads/green/threads.h"
72 # endif
73 #endif
74
75 #include "vm/exceptions.h"
76 #include "vm/method.h"
77 #include "vm/options.h"
78 #include "vm/statistics.h"
79 #include "vm/jit/codegen.inc.h"
80 #include "vm/jit/disass.h"
81 #include "vm/jit/jit.h"
82 #include "vm/jit/stacktrace.h"
83
84
85 /* in this tree we store all method addresses *********************************/
86
87 #if defined(__I386__) || defined(__X86_64__) || defined(__INTRP__)
88 static struct avl_table *methodtree = NULL;
89 static int methodtree_comparator(const void *pc, const void *element,
90                                                                  void *param);
91 #endif
92
93
94 /* codegen_init ****************************************************************
95
96    TODO
97
98 *******************************************************************************/
99
100 void codegen_init(void)
101 {
102 #if defined(__I386__) || defined(__X86_64__) || defined(__INTRP__)
103         /* this tree is global, not method specific */
104
105         if (!methodtree) {
106 #if !defined(__INTRP__)
107                 methodtree_element *mte;
108 #endif
109
110                 methodtree = avl_create(methodtree_comparator, NULL, NULL);
111
112 #if !defined(__INTRP__)
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 #endif /* !defined(__INTRP__) */
131         }
132 #endif
133 }
134
135
136 /* codegen_setup **************************************************************
137
138    allocates and initialises code area, data area and references
139
140 *******************************************************************************/
141
142 void codegen_setup(methodinfo *m, codegendata *cd, t_inlining_globals *id)
143 {
144         cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
145         cd->mcodesize = MCODEINITSIZE;
146         
147         cd->dsegtop = DMNEW(u1, DSEGINITSIZE);
148         cd->dsegsize = DSEGINITSIZE;
149         cd->dsegtop += cd->dsegsize;
150         cd->dseglen = 0;
151
152         cd->jumpreferences = NULL;
153         cd->datareferences = NULL;
154         cd->xboundrefs = 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 ************************************************************
235
236    Doubles code area.
237
238 *******************************************************************************/
239
240 static s4 *codegen_increase(codegendata *cd, u1 *mcodeptr)
241 {
242         u1 *oldmcodebase;
243
244         /* save old mcodebase pointer */
245
246         oldmcodebase = cd->mcodebase;
247
248         /* reallocate to new, doubled memory */
249
250         cd->mcodebase = DMREALLOC(cd->mcodebase,
251                                                           u1,
252                                                           cd->mcodesize,
253                                                           cd->mcodesize * 2);
254         cd->mcodesize *= 2;
255         cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
256
257 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__)
258         /* adjust the pointer to the last patcher position */
259
260         cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
261 #endif
262
263         /* return the new mcodeptr */
264
265         return (s4 *) (cd->mcodebase + (mcodeptr - oldmcodebase));
266 }
267
268
269 /* desg_increase ***************************************************************
270
271    Doubles data area.
272
273 *******************************************************************************/
274
275 static void dseg_increase(codegendata *cd)
276 {
277         u1 *newstorage;
278
279         newstorage = DMNEW(u1, cd->dsegsize * 2);
280
281         MCOPY(newstorage + cd->dsegsize, cd->dsegtop - cd->dsegsize, u1,
282                   cd->dsegsize);
283
284         cd->dsegtop = newstorage;
285         cd->dsegsize *= 2;
286         cd->dsegtop += cd->dsegsize;
287 }
288
289
290 static s4 dseg_adds4_increase(codegendata *cd, s4 value)
291 {
292         dseg_increase(cd);
293
294         *((s4 *) (cd->dsegtop - cd->dseglen)) = value;
295
296         return -(cd->dseglen);
297 }
298
299
300 static s4 dseg_adds4(codegendata *cd, s4 value)
301 {
302         s4 *dataptr;
303
304         cd->dseglen += 4;
305         dataptr = (s4 *) (cd->dsegtop - cd->dseglen);
306
307         if (cd->dseglen > cd->dsegsize)
308                 return dseg_adds4_increase(cd, value);
309
310         *dataptr = value;
311
312         return -(cd->dseglen);
313 }
314
315
316 #if !defined(__I386__) && !defined(__POWERPC__)
317 static s4 dseg_adds8_increase(codegendata *cd, s8 value)
318 {
319         dseg_increase(cd);
320
321         *((s8 *) (cd->dsegtop - cd->dseglen)) = value;
322
323         return -(cd->dseglen);
324 }
325
326
327 static s4 dseg_adds8(codegendata *cd, s8 value)
328 {
329         s8 *dataptr;
330
331         cd->dseglen = ALIGN(cd->dseglen + 8, 8);
332         dataptr = (s8 *) (cd->dsegtop - cd->dseglen);
333
334         if (cd->dseglen > cd->dsegsize)
335                 return dseg_adds8_increase(cd, value);
336
337         *dataptr = value;
338
339         return -(cd->dseglen);
340 }
341 #endif
342
343
344 #if !defined(__XDSPCORE__)
345 static s4 dseg_addfloat_increase(codegendata *cd, float value)
346 {
347         dseg_increase(cd);
348
349         *((float *) (cd->dsegtop - cd->dseglen)) = value;
350
351         return -(cd->dseglen);
352 }
353
354
355 static s4 dseg_addfloat(codegendata *cd, float value)
356 {
357         float *dataptr;
358
359         cd->dseglen += 4;
360         dataptr = (float *) (cd->dsegtop - cd->dseglen);
361
362         if (cd->dseglen > cd->dsegsize)
363                 return dseg_addfloat_increase(cd, value);
364
365         *dataptr = value;
366
367         return -(cd->dseglen);
368 }
369
370
371 static s4 dseg_adddouble_increase(codegendata *cd, double value)
372 {
373         dseg_increase(cd);
374
375         *((double *) (cd->dsegtop - cd->dseglen)) = value;
376
377         return -(cd->dseglen);
378 }
379
380
381 static s4 dseg_adddouble(codegendata *cd, double value)
382 {
383         double *dataptr;
384
385         cd->dseglen = ALIGN(cd->dseglen + 8, 8);
386         dataptr = (double *) (cd->dsegtop - cd->dseglen);
387
388         if (cd->dseglen > cd->dsegsize)
389                 return dseg_adddouble_increase(cd, value);
390
391         *dataptr = value;
392
393         return -(cd->dseglen);
394 }
395 #endif /* !defined(__XDSPCORE__) */
396
397
398 static void dseg_addtarget(codegendata *cd, basicblock *target)
399 {
400         jumpref *jr;
401
402         jr = DNEW(jumpref);
403         jr->tablepos = dseg_addaddress(cd, NULL);
404         jr->target = target;
405         jr->next = cd->jumpreferences;
406         cd->jumpreferences = jr;
407 }
408
409
410 #if defined(__I386__) || defined(__X86_64__)
411 static void dseg_adddata(codegendata *cd, u1 *ptr)
412 {
413         dataref *dr;
414
415         dr = DNEW(dataref);
416         dr->pos = (u1 *) (ptr - cd->mcodebase);
417         dr->next = cd->datareferences;
418         cd->datareferences = dr;
419 }
420 #endif
421
422
423 /* dseg_addlinenumbertablesize *************************************************
424
425    XXX
426
427 *******************************************************************************/
428
429 static void dseg_addlinenumbertablesize(codegendata *cd)
430 {
431 #if SIZEOF_VOID_P == 8
432         /* 4-byte ALIGNMENT PADDING */
433
434         dseg_adds4(cd, 0);
435 #endif
436
437         cd->linenumbertablesizepos = dseg_addaddress(cd, NULL);
438         cd->linenumbertablestartpos = dseg_addaddress(cd, NULL);
439
440 #if SIZEOF_VOID_P == 8
441         /* 4-byte ALIGNMENT PADDING */
442
443         dseg_adds4(cd, 0);
444 #endif
445 }
446
447
448 static void dseg_addlinenumber(codegendata *cd, u2 linenumber, u1 *ptr)
449 {
450         linenumberref *lr;
451
452         lr = DNEW(linenumberref);
453         lr->linenumber = linenumber;
454         lr->tablepos = 0;
455         lr->targetmpc = (ptr - cd->mcodebase);
456         lr->next = cd->linenumberreferences;
457         cd->linenumberreferences = lr;
458 }
459
460
461 /* we need this function externally on i386 and x86_64, but keep the call fast
462    on alpha... */
463
464 #if defined(__I386__) || defined(__X86_64__)
465 void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
466 #else
467 static void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
468 #endif
469 {
470         s4 branchpos;
471
472         branchpos = (u1 *) branchptr - cd->mcodebase;
473
474 #if !defined(__INTRP__)
475         /* The interpreter uses absolute branches, so we do branch resolving */
476         /* after the code and data segment move. */
477
478         /* Check if the target basicblock has already a start pc, so the jump is  */
479         /* backward and we can resolve it immediately.                            */
480
481         if (target->mpc >= 0) {
482                 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
483                                                   branchpos,
484                                                   target->mpc);
485
486         } else
487 #endif
488         {
489                 branchref *br = DNEW(branchref);
490
491                 br->branchpos = branchpos;
492                 br->next = target->branchrefs;
493                 target->branchrefs = br;
494         }
495 }
496
497
498 static void codegen_addxboundrefs(codegendata *cd, void *branchptr, s4 reg)
499 {
500         s4 branchpos;
501         branchref *br;
502
503         branchpos = (u1 *) branchptr - cd->mcodebase;
504
505         br = DNEW(branchref);
506         br->branchpos = branchpos;
507         br->reg = reg;
508         br->next = cd->xboundrefs;
509         cd->xboundrefs = br;
510 }
511
512
513 static void codegen_addxnullrefs(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->xnullrefs;
523         cd->xnullrefs = br;
524 }
525
526
527 static void codegen_addxcastrefs(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->xcastrefs;
537         cd->xcastrefs = br;
538 }
539
540
541 /* codegen_addxstorerefs *******************************************************
542
543    Adds an ArrayStoreException branch to the list.
544
545 *******************************************************************************/
546
547 static void codegen_addxstorerefs(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->xstorerefs;
557         cd->xstorerefs = br;
558 }
559
560
561 /* codegen_addxdivrefs *********************************************************
562
563    Adds an ArithmeticException branch to the list.
564
565 *******************************************************************************/
566
567 static void codegen_addxdivrefs(codegendata *cd, void *branchptr)
568 {
569         s4 branchpos;
570         branchref *br;
571
572         branchpos = (u1 *) branchptr - cd->mcodebase;
573
574         br = DNEW(branchref);
575         br->branchpos = branchpos;
576         br->next = cd->xdivrefs;
577         cd->xdivrefs = br;
578 }
579
580
581 static void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
582 {
583         s4 branchpos;
584         branchref *br;
585
586         branchpos = (u1 *) branchptr - cd->mcodebase;
587
588         br = DNEW(branchref);
589         br->branchpos = branchpos;
590         br->next = cd->xexceptionrefs;
591         cd->xexceptionrefs = br;
592 }
593
594
595 /* codegen_addpatchref *********************************************************
596
597    Adds a new patcher reference to the list of patching positions.
598
599 *******************************************************************************/
600
601 static void codegen_addpatchref(codegendata *cd, voidptr branchptr,
602                                                                 functionptr patcher, voidptr ref, s4 disp)
603 {
604         patchref *pr;
605         s4        branchpos;
606
607         branchpos = (u1 *) branchptr - cd->mcodebase;
608
609         pr = DNEW(patchref);
610
611         pr->branchpos = branchpos;
612         pr->patcher   = patcher;
613         pr->ref       = ref;
614         pr->disp      = disp;
615
616         pr->next      = cd->patchrefs;
617         cd->patchrefs = pr;
618
619 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__)
620         /* On some architectures the patcher stub call instruction might
621         be longer than the actual instruction generated.  On this
622         architectures we store the last patcher call position and after
623         the basic block code generation is completed, we check the range
624         and maybe generate some nop's. */
625
626         cd->lastmcodeptr = ((u1 *) branchptr) + PATCHER_CALL_SIZE;
627 #endif
628 }
629
630
631 /* codegen_createlinenumbertable ***********************************************
632
633    Creates a line number table in the data segment from the created
634    entries in linenumberreferences.
635
636 *******************************************************************************/
637
638 static void codegen_createlinenumbertable(codegendata *cd)
639 {
640         linenumberref *lr;
641
642         for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
643                 lr->tablepos = dseg_addaddress(cd, NULL);
644
645                 if (cd->linenumbertab == 0)
646                         cd->linenumbertab = lr->tablepos;
647
648                 dseg_addaddress(cd, lr->linenumber);
649         }
650 }
651
652
653 #if defined(__I386__) || defined(__X86_64__) || defined(__INTRP__)
654 /* methodtree_comparator *******************************************************
655
656    XXX
657
658 *******************************************************************************/
659
660 static int methodtree_comparator(const void *pc, const void *element, void *param)
661 {
662         methodtree_element *mte;
663         methodtree_element *mtepc;
664
665         mte = (methodtree_element *) element;
666         mtepc = (methodtree_element *) pc;
667
668         /* compare both startpc and endpc of pc, even if they have the same value,
669            otherwise the avl_probe sometimes thinks the element is already in the
670            tree */
671
672         if ((long) mte->startpc <= (long) mtepc->startpc &&
673                 (long) mtepc->startpc <= (long) mte->endpc &&
674                 (long) mte->startpc <= (long) mtepc->endpc &&
675                 (long) mtepc->endpc <= (long) mte->endpc) {
676                 return 0;
677
678         } else if ((long) mtepc->startpc < (long) mte->startpc) {
679                 return -1;
680
681         } else {
682                 return 1;
683         }
684 }
685
686
687 /* codegen_insertmethod ********************************************************
688
689    XXX
690
691 *******************************************************************************/
692
693 void codegen_insertmethod(functionptr startpc, functionptr endpc)
694 {
695         methodtree_element *mte;
696
697 #if defined(USE_THREADS)
698 #if defined(NATIVE_THREADS)
699         tables_lock();
700 #endif
701 #endif
702
703         mte = NEW(methodtree_element);
704         mte->startpc = startpc;
705         mte->endpc = endpc;
706
707         if (avl_insert(methodtree, mte)) {
708 #if defined(USE_THREADS)
709 #if defined(NATIVE_THREADS)
710                 tables_unlock();
711 #endif
712 #endif
713                 assert(0);
714                 throw_cacao_exception_exit(string_java_lang_InternalError,
715                                                                    "duplicate entry");
716         }
717
718 #if defined(USE_THREADS)
719 #if defined(NATIVE_THREADS)
720         tables_unlock();
721 #endif
722 #endif
723 }
724
725
726 /* codegen_findmethod **********************************************************
727
728    XXX
729
730 *******************************************************************************/
731
732 functionptr codegen_findmethod(functionptr pc)
733 {
734         methodtree_element *mtepc;
735         methodtree_element *mte;
736
737 #if defined(USE_THREADS)
738 #if defined(NATIVE_THREADS)
739         tables_lock();
740 #endif
741 #endif
742
743         mtepc = NEW(methodtree_element);
744         mtepc->startpc = pc;
745         mtepc->endpc = pc;
746
747         mte = avl_find(methodtree, mtepc);
748
749         FREE(mtepc, methodtree_element);
750
751         if (!mte) {
752 #if defined(USE_THREADS)
753 #if defined(NATIVE_THREADS)
754                 tables_unlock();
755 #endif
756 #endif
757                 printf("Cannot find Java function at %p\n", (void *) (ptrint) pc);
758                 assert(0);
759                 throw_cacao_exception_exit(string_java_lang_InternalError,
760                                                                    "Cannot find Java function at %p", pc);
761         }
762
763 #if defined(USE_THREADS)
764 #if defined(NATIVE_THREADS)
765         tables_unlock();
766 #endif
767 #endif
768
769         return mte->startpc;
770 }
771 #endif /* defined(__I386__) || defined(__X86_64__) || defined(__INTRP__) */
772
773
774 /* codegen_finish **************************************************************
775
776    Finishes the code generation. A new memory, large enough for both
777    data and code, is allocated and data and code are copied together
778    to their final layout, unresolved jumps are resolved, ...
779
780 *******************************************************************************/
781
782 static void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
783 {
784         jumpref     *jr;
785         functionptr  epoint;
786         s4           extralen;
787         s4           alignedlen;
788
789 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
790         extralen = sizeof(threadcritnode) * cd->threadcritcount;
791 #else
792         extralen = 0;
793 #endif
794
795 #if defined(STATISTICS)
796         if (opt_stat) {
797                 count_code_len += mcodelen;
798                 count_data_len += cd->dseglen;
799         }
800 #endif
801
802         cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
803         alignedlen = ALIGN(mcodelen, MAX_ALIGN) + cd->dseglen;
804
805         /* allocate new memory */
806
807         m->mcodelength = mcodelen + cd->dseglen;
808         m->mcode = (functionptr) (ptrint) CNEW(u1, alignedlen + extralen);
809
810         /* copy data and code to their new location */
811
812         MCOPY((void *) (ptrint) m->mcode, cd->dsegtop - cd->dseglen, u1,
813                   cd->dseglen);
814         MCOPY((void *) ((ptrint) m->mcode + cd->dseglen), cd->mcodebase, u1,
815                   mcodelen);
816
817         m->entrypoint = epoint = (functionptr) ((ptrint) m->mcode + cd->dseglen);
818
819         /* jump table resolving */
820
821         jr = cd->jumpreferences;
822         while (jr != NULL) {
823                 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
824                         (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
825                 jr = jr->next;
826         }
827
828         /* line number table resolving */
829         {
830                 linenumberref *lr;
831                 ptrint lrtlen = 0;
832
833                 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
834                         lrtlen++;
835                         *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
836                                 (functionptr) ((ptrint) epoint + (ptrint) lr->targetmpc);
837                 }
838                 
839                 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
840                         (functionptr) ((ptrint) epoint + cd->linenumbertab);
841
842                 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
843         }
844
845 #if defined(__I386__) || defined(__X86_64__) || defined(__INTRP__)
846         /* add method into methodtree to find the entrypoint */
847
848         codegen_insertmethod(m->entrypoint,
849                                                  (functionptr) ((ptrint) m->entrypoint + mcodelen));
850 #endif
851
852 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__)
853         {
854                 dataref *dr;
855
856                 /* data segment references resolving */
857
858                 dr = cd->datareferences;
859                 while (dr != NULL) {
860                         *((functionptr *) ((ptrint) epoint + (ptrint) dr->pos -
861                                                            SIZEOF_VOID_P)) = epoint;
862                         dr = dr->next;
863                 }
864         }
865 #endif
866
867 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
868         {
869                 threadcritnode *n = (threadcritnode *) ((ptrint) m->mcode + alignedlen);
870                 s4 i;
871                 threadcritnodetemp *nt = cd->threadcrit;
872
873                 for (i = 0; i < cd->threadcritcount; i++) {
874                         n->mcodebegin = (u1 *) (ptrint) m->mcode + nt->mcodebegin;
875                         n->mcodeend = (u1 *) (ptrint) m->mcode + nt->mcodeend;
876                         n->mcoderestart = (u1 *) (ptrint) m->mcode + nt->mcoderestart;
877                         thread_registercritical(n);
878                         n++;
879                         nt = nt->next;
880                 }
881         }
882 #endif
883 }
884
885
886 void dseg_display(methodinfo *m, codegendata *cd)
887 {
888         s4 *s4ptr;
889         s4 i;
890         
891         s4ptr = (s4 *) (ptrint) m->mcode;
892
893         printf("  --- dump of datasegment\n");
894         for (i = cd->dseglen; i > 0 ; i -= 4) {
895 #if SIZEOF_VOID_P == 8
896                 printf("0x%016lx:   -%6x (%6d): %8x\n",
897                            (ptrint) s4ptr, i, i, (s4) *s4ptr);
898 #else
899                 printf("0x%08x:   -%6x (%6d): %8x\n",
900                            (ptrint) s4ptr, i, i, (s4) *s4ptr);
901 #endif
902                 s4ptr++;
903         }
904
905         printf("  --- begin of data segment: %p\n", (void *) s4ptr);
906 }
907
908
909
910 /* codegen_createnativestub ****************************************************
911
912    Wrapper for createnativestub.
913
914 *******************************************************************************/
915
916 functionptr codegen_createnativestub(functionptr f, methodinfo *m)
917 {
918         codegendata        *cd;
919         registerdata       *rd;
920         t_inlining_globals *id;
921         s4                  dumpsize;
922         methoddesc         *md;
923         methoddesc         *nmd;        
924         s4                  nativeparams;
925
926         /* mark dump memory */
927
928         dumpsize = dump_size();
929
930         cd = DNEW(codegendata);
931         rd = DNEW(registerdata);
932         id = DNEW(t_inlining_globals);
933
934         /* setup code generation stuff */
935
936         inlining_setup(m, id);
937 #if !defined(__INTRP__)
938         reg_setup(m, rd, id);
939 #endif
940         codegen_setup(m, cd, id);
941                                                 
942         /* create new method descriptor with additional native parameters */
943
944         md = m->parseddesc;
945         nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
946         
947         nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
948                                                            md->paramcount * sizeof(typedesc) +
949                                                            nativeparams * sizeof(typedesc));
950
951         nmd->paramcount = md->paramcount + nativeparams;
952
953         nmd->params = DMNEW(paramdesc, nmd->paramcount);
954
955         nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer            */
956
957         if (m->flags & ACC_STATIC)
958                 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer              */
959
960         MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
961                   md->paramcount);
962
963         md_param_alloc(nmd);
964
965         /* generate the code */
966
967         m->entrypoint = createnativestub(f, m, cd, rd, nmd);
968
969 #if defined(STATISTICS)
970         if (opt_stat)
971                 count_nstub_len += m->mcodelength;
972 #endif
973
974         /* disassemble native stub */
975
976         if (opt_shownativestub) {
977                 codegen_disassemble_nativestub(m,
978                                                                            (u1 *) (ptrint) m->entrypoint,
979                                                                            (u1 *) (ptrint) m->entrypoint + (m->mcodelength - cd->dseglen));
980
981                 /* show data segment */
982
983                 if (opt_showddatasegment)
984                         dseg_display(m, cd);
985         }
986
987         /* release memory */
988
989         dump_release(dumpsize);
990
991         /* return native stub entry point */
992
993         return m->entrypoint;
994 }
995
996
997 /* codegen_disassemble_nativestub **********************************************
998
999    Disassembles the generated native stub.
1000
1001 *******************************************************************************/
1002
1003 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
1004 {
1005         printf("Native stub: ");
1006         utf_fprint_classname(stdout, m->class->name);
1007         printf(".");
1008         utf_fprint(stdout, m->name);
1009         utf_fprint(stdout, m->descriptor);
1010         printf("\n\nLength: %d\n\n", (s4) (end - start));
1011
1012         disassemble(start, end);
1013 }
1014
1015
1016 /* codegen_start_native_call ***************************************************
1017
1018    Prepares the stuff required for a native (JNI) function call:
1019
1020    - adds a stackframe info structure to the chain, for stacktraces
1021    - prepares the local references table on the stack
1022
1023    The layout of the native stub stackframe should look like this:
1024
1025    +---------------------------+ <- SP (of parent Java function)
1026    | return address            |
1027    +---------------------------+
1028    |                           |
1029    | stackframe info structure |
1030    |                           |
1031    +---------------------------+
1032    |                           |
1033    | local references table    |
1034    |                           |
1035    +---------------------------+
1036    |                           |
1037    | arguments (if any)        |
1038    |                           |
1039    +---------------------------+ <- SP (native stub)
1040
1041 *******************************************************************************/
1042
1043 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, functionptr ra)
1044 {
1045         stackframeinfo *sfi;
1046         localref_table *lrt;
1047         nativethread   *info;
1048
1049         /* get data structures from stack */
1050
1051         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1052         lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
1053                                                           sizeof(localref_table));
1054
1055         /* get thread info */
1056
1057         info = THREADINFO;
1058
1059         /* add a stackframeinfo to the chain */
1060
1061         stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1062
1063         /* add current JNI local references table to this thread */
1064
1065         lrt->capacity    = LOCALREFTABLE_CAPACITY;
1066         lrt->used        = 0;
1067         lrt->localframes = 1;
1068         lrt->prev        = info->_localref_table;
1069
1070         /* clear the references array (memset is faster the a for-loop) */
1071
1072         MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1073
1074         info->_localref_table = lrt;
1075 }
1076
1077
1078 /* codegen_finish_native_call **************************************************
1079
1080    Removes the stuff required for a native (JNI) function call.
1081
1082 *******************************************************************************/
1083
1084 void codegen_finish_native_call(u1 *datasp)
1085 {
1086         stackframeinfo *sfi;
1087         localref_table *lrt;
1088         nativethread   *info;
1089         s4              localframes;
1090
1091         /* get data structures from stack */
1092
1093         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1094         lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
1095                                                           sizeof(localref_table));
1096
1097         /* get thread info */
1098
1099         info = THREADINFO;
1100
1101         /* remove current stackframeinfo from chain */
1102
1103         info->_stackframeinfo = sfi->prev;
1104
1105         /* release JNI local references tables for this thread */
1106
1107         lrt = info->_localref_table;
1108
1109         /* got through all current local frames */
1110
1111         for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1112                 lrt = lrt->prev;
1113         }
1114
1115         /* now store the previous local frames in the thread structure */
1116
1117         info->_localref_table = lrt;
1118 }
1119
1120
1121 /* removecompilerstub **********************************************************
1122
1123    Deletes a compilerstub from memory (simply by freeing it).
1124
1125 *******************************************************************************/
1126
1127 void removecompilerstub(functionptr stub)
1128 {
1129         /* pass size 1 to keep the intern function happy */
1130
1131         CFREE((void *) (ptrint) stub, 1);
1132 }
1133
1134
1135 /* removenativestub ************************************************************
1136
1137    Removes a previously created native-stub from memory.
1138     
1139 *******************************************************************************/
1140
1141 void removenativestub(functionptr stub)
1142 {
1143         /* pass size 1 to keep the intern function happy */
1144
1145         CFREE((void *) (ptrint) stub, 1);
1146 }
1147
1148
1149 /* reg_of_var:
1150     This function determines a register, to which the result of an operation
1151     should go, when it is ultimatively intended to store the result in
1152     pseudoregister v.
1153     If v is assigned to an actual register, this register will be returned.
1154     Otherwise (when v is spilled) this function returns tempregnum.
1155     If not already done, regoff and flags are set in the stack location.
1156 */        
1157 /*  On ARM we have to check if a long/double variable is splitted
1158     across reg/stack (HIGH_REG == REG_SPLIT). We return the actual register
1159     of v for LOW_REG and the tempregnum for HIGH_REG in such cases.
1160     (michi 2005/07/24)
1161 */
1162
1163 static int reg_of_var(registerdata *rd, stackptr v, int tempregnum)
1164 {
1165         varinfo *var;
1166
1167         switch (v->varkind) {
1168         case TEMPVAR:
1169                 if (!(v->flags & INMEMORY))
1170                         return(v->regoff);
1171                 break;
1172
1173         case STACKVAR:
1174                 var = &(rd->interfaces[v->varnum][v->type]);
1175                 v->regoff = var->regoff;
1176                 if (!(var->flags & INMEMORY))
1177                         return(var->regoff);
1178                 break;
1179
1180         case LOCALVAR:
1181                 var = &(rd->locals[v->varnum][v->type]);
1182                 v->regoff = var->regoff;
1183                 if (!(var->flags & INMEMORY)) {
1184 #if defined(__ARM__) && defined(__ARMEL__)
1185                         if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
1186                                 return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
1187 #endif
1188 #if defined(__ARM__) && defined(__ARMEB__)
1189                         if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
1190                                 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
1191 #endif
1192                         return(var->regoff);
1193                 }
1194                 break;
1195
1196         case ARGVAR:
1197                 if (!(v->flags & INMEMORY)) {
1198 #if defined(__ARM__) && defined(__ARMEL__)
1199                         if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
1200                                 return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
1201 #endif
1202 #if defined(__ARM__) && defined(__ARMEB__)
1203                         if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
1204                                 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
1205 #endif
1206                         return(v->regoff);
1207                 }
1208                 break;
1209         }
1210 #ifdef STATISTICS
1211         if (opt_stat)
1212                 count_spills_read++;
1213 #endif
1214         v->flags |= INMEMORY;
1215         return tempregnum;
1216 }
1217
1218
1219 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1220 static void codegen_threadcritrestart(codegendata *cd, int offset)
1221 {
1222         cd->threadcritcurrent.mcoderestart = offset;
1223 }
1224
1225
1226 static void codegen_threadcritstart(codegendata *cd, int offset)
1227 {
1228         cd->threadcritcurrent.mcodebegin = offset;
1229 }
1230
1231
1232 static void codegen_threadcritstop(codegendata *cd, int offset)
1233 {
1234         cd->threadcritcurrent.next = cd->threadcrit;
1235         cd->threadcritcurrent.mcodeend = offset;
1236         cd->threadcrit = DNEW(threadcritnodetemp);
1237         *(cd->threadcrit) = cd->threadcritcurrent;
1238         cd->threadcritcount++;
1239 }
1240 #endif
1241
1242
1243 /*
1244  * These are local overrides for various environment variables in Emacs.
1245  * Please do not remove this and leave it at the end of the file, where
1246  * Emacs will automagically detect them.
1247  * ---------------------------------------------------------------------
1248  * Local variables:
1249  * mode: c
1250  * indent-tabs-mode: t
1251  * c-basic-offset: 4
1252  * tab-width: 4
1253  * End:
1254  */