999c347b1c1fd7c805a27df9e8beebb28ddc6dba
[cacao.git] / src / vm / jit / codegen.inc
1 /* vm/jit/codegen.inc - architecture independent code generator
2
3    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4    Institut f. Computersprachen, TU Wien
5    R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Probst,
6    S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich,
7    J. Wenninger
8
9    This file is part of CACAO.
10
11    This program is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public License as
13    published by the Free Software Foundation; either version 2, or (at
14    your option) any later version.
15
16    This program is distributed in the hope that it will be useful, but
17    WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24    02111-1307, USA.
25
26    Contact: cacao@complang.tuwien.ac.at
27
28    Authors: Reinhard Grafl
29             Andreas  Krall
30
31    Changes: Christian Thalinger
32             Joseph Wenninger
33
34    All functions assume the following code area / data area layout:
35
36    +-----------+
37    |           |
38    | code area | code area grows to higher addresses
39    |           |
40    +-----------+ <-- start of procedure
41    |           |
42    | data area | data area grows to lower addresses
43    |           |
44    +-----------+
45
46    The functions first write into a temporary code/data area allocated by
47    "codegen_init". "codegen_finish" copies the code and data area into permanent
48    memory. All functions writing values into the data area return the offset
49    relative the begin of the code area (start of procedure).    
50
51    $Id: codegen.inc 1683 2004-12-05 21:33:36Z jowenn $
52
53 */
54
55 #ifndef _CODEGEN_INC_H_
56 #define _CODEGEN_INC_H_
57
58 #include <string.h>
59
60 #if !defined(STATIC_CLASSPATH)
61 # include <dlfcn.h>
62 #endif
63
64 #include "mm/memory.h"
65 #include "toolbox/avl.h"
66 #include "toolbox/logging.h"
67 #include "native/native.h"
68
69 #if defined(USE_THREADS)
70 # if defined(NATIVE_THREADS)
71 #  include "threads/native/threads.h"
72 # else
73 #  include "threads/green/threads.h"
74 # endif
75 #endif
76
77 #include "vm/exceptions.h"
78 #include "vm/options.h"
79 #include "vm/statistics.h"
80 #include "vm/jit/codegen.inc.h"
81
82
83 /* in this tree we store all method addresses *********************************/
84
85 #if defined(__I386__) || defined(__X86_64__)
86 static struct avl_table *methodtree = NULL;
87 static int methodtree_comparator(const void *pc, const void *element,
88                                                                  void *param);
89 #endif
90
91
92 /* codegen_init ****************************************************************
93
94    TODO
95
96 *******************************************************************************/
97
98 void codegen_init()
99 {
100 #if defined(__I386__) || defined(__X86_64__)
101         /* this tree is global, not method specific */
102         if (!methodtree) {
103                 methodtree_element *mte;
104
105                 methodtree = avl_create(methodtree_comparator, NULL, NULL);
106
107                 mte = NEW(methodtree_element);
108
109                 mte->startpc = (functionptr) asm_calljavafunction;
110                 mte->endpc = (functionptr) ((long) asm_calljavafunction2 - 1);
111
112                 avl_insert(methodtree, mte);
113
114                 mte = NEW(methodtree_element);
115
116                 mte->startpc = (functionptr) asm_calljavafunction2;
117                 mte->endpc = (functionptr) ((long) asm_call_jit_compiler - 1);
118
119                 avl_insert(methodtree, mte);
120         }
121 #endif
122 }
123
124
125 /* codegen_setup **************************************************************
126
127    allocates and initialises code area, data area and references
128
129 *******************************************************************************/
130
131 void codegen_setup(methodinfo *m, codegendata *cd, t_inlining_globals *id)
132 {
133         cd->mcodebase = MNEW(u1, MCODEINITSIZE);
134         cd->mcodesize = MCODEINITSIZE;
135         
136         cd->dsegtop = MNEW(u1, DSEGINITSIZE);
137         cd->dsegsize = DSEGINITSIZE;
138         cd->dsegtop += cd->dsegsize;
139         cd->dseglen = 0;
140
141         cd->jumpreferences = NULL;
142         cd->datareferences = NULL;
143         cd->xboundrefs = NULL;
144         cd->xcheckarefs = NULL;
145         cd->xnullrefs = NULL;
146         cd->xcastrefs = NULL;
147         cd->xdivrefs = NULL;
148         cd->xexceptionrefs = NULL;
149         cd->clinitrefs = NULL;
150
151         cd->linenumberreferences = NULL;
152         cd->linenumbertablesizepos = 0;
153         cd->linenumbertablestartpos = 0;
154         cd->linenumbertab = 0;
155         
156         cd->method = m;
157         cd->exceptiontable = 0;
158         cd->exceptiontablelength = 0;
159
160         if (useinlining && id) {
161                 if (id->cumextablelength > 0) {
162                         cd->exceptiontablelength = id->cumextablelength;
163                         cd->exceptiontable  = DMNEW(exceptiontable, id->cumextablelength + 1);
164                 }
165
166         } else if (id && (id->method->exceptiontablelength >0)) {
167                 cd->exceptiontablelength = m->exceptiontablelength;
168                 cd->exceptiontable  = DMNEW(exceptiontable, m->exceptiontablelength + 1);
169         }
170
171         if (id) {
172                 cd->maxstack = id->cummaxstack;
173                 cd->maxlocals = id->cumlocals;
174         } else {
175                 cd->maxstack = m->maxstack;
176                 cd->maxlocals = m->maxlocals;
177         }
178
179 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
180         cd->threadcritcurrent.next = NULL;
181         cd->threadcritcount = 0;
182 #endif
183 }
184
185
186 /* codegen_free ****************************************************************
187
188    releases temporary code and data area
189
190 *******************************************************************************/
191
192 void codegen_free(methodinfo *m, codegendata *cd)
193 {
194         if (cd) {
195 #if 0
196                 if (cd->exceptiontablelength) {
197                         cd->exceptiontablelength = m->exceptiontablelength;
198                         MFREE(cd->exceptiontable, exceptiontable, cd->exceptiontablelength + 1);
199                         cd->exceptiontable = 0;
200                         cd->exceptiontablelength = 0;
201                 }
202 #endif
203
204                 if (cd->mcodebase) {
205                         MFREE(cd->mcodebase, u1, cd->mcodesize);
206                         cd->mcodebase = NULL;
207                 }
208
209                 if (cd->dsegtop) {
210                         MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
211                         cd->dsegtop = NULL;
212                 }
213         }
214 }
215
216
217 /* codegen_close ***************************************************************
218
219    TODO
220
221 *******************************************************************************/
222
223 void codegen_close()
224 {
225         /* TODO: release avl tree on i386 and x86_64 */
226 }
227
228
229 /* codegen_increase doubles code area                                         */
230
231 static s4 *codegen_increase(codegendata *cd, u1 *codeptr)
232 {
233         long len;
234
235         len = codeptr - cd->mcodebase;
236         cd->mcodebase = MREALLOC(cd->mcodebase,
237                                                          u1,
238                                                          cd->mcodesize,
239                                                          cd->mcodesize * 2);
240         cd->mcodesize *= 2;
241         cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
242
243         return (s4 *) (cd->mcodebase + len);
244 }
245
246
247 /* desg_increase doubles data area                                            */
248
249 static void dseg_increase(codegendata *cd)
250 {
251         u1 *newstorage;
252
253         newstorage = MNEW(u1, cd->dsegsize * 2);
254
255         memcpy(newstorage + cd->dsegsize, cd->dsegtop - cd->dsegsize, cd->dsegsize);
256         MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
257
258         cd->dsegtop = newstorage;
259         cd->dsegsize *= 2;
260         cd->dsegtop += cd->dsegsize;
261 }
262
263
264 static s4 dseg_adds4_increase(codegendata *cd, s4 value)
265 {
266         dseg_increase(cd);
267
268         *((s4 *) (cd->dsegtop - cd->dseglen)) = value;
269
270         return -(cd->dseglen);
271 }
272
273
274 static s4 dseg_adds4(codegendata *cd, s4 value)
275 {
276         s4 *dataptr;
277
278         cd->dseglen += 4;
279         dataptr = (s4 *) (cd->dsegtop - cd->dseglen);
280
281         if (cd->dseglen > cd->dsegsize)
282                 return dseg_adds4_increase(cd, value);
283
284         *dataptr = value;
285
286         return -(cd->dseglen);
287 }
288
289
290 #if !defined(__I386__)
291 static s4 dseg_adds8_increase(codegendata *cd, s8 value)
292 {
293         dseg_increase(cd);
294
295         *((s8 *) (cd->dsegtop - cd->dseglen)) = value;
296
297         return -(cd->dseglen);
298 }
299
300
301 static s4 dseg_adds8(codegendata *cd, s8 value)
302 {
303         s8 *dataptr;
304
305         cd->dseglen = ALIGN(cd->dseglen + 8, 8);
306         dataptr = (s8 *) (cd->dsegtop - cd->dseglen);
307
308         if (cd->dseglen > cd->dsegsize)
309                 return dseg_adds8_increase(cd, value);
310
311         *dataptr = value;
312
313         return -(cd->dseglen);
314 }
315 #endif
316
317
318 static s4 dseg_addfloat_increase(codegendata *cd, float value)
319 {
320         dseg_increase(cd);
321
322         *((float *) (cd->dsegtop - cd->dseglen)) = value;
323
324         return -(cd->dseglen);
325 }
326
327
328 static s4 dseg_addfloat(codegendata *cd, float value)
329 {
330         float *dataptr;
331
332         cd->dseglen += 4;
333         dataptr = (float *) (cd->dsegtop - cd->dseglen);
334
335         if (cd->dseglen > cd->dsegsize)
336                 return dseg_addfloat_increase(cd, value);
337
338         *dataptr = value;
339
340         return -(cd->dseglen);
341 }
342
343
344 static s4 dseg_adddouble_increase(codegendata *cd, double value)
345 {
346         dseg_increase(cd);
347
348         *((double *) (cd->dsegtop - cd->dseglen)) = value;
349
350         return -(cd->dseglen);
351 }
352
353
354 static s4 dseg_adddouble(codegendata *cd, double value)
355 {
356         double *dataptr;
357
358         cd->dseglen = ALIGN(cd->dseglen + 8, 8);
359         dataptr = (double *) (cd->dsegtop - cd->dseglen);
360
361         if (cd->dseglen > cd->dsegsize)
362                 return dseg_adddouble_increase(cd, value);
363
364         *dataptr = value;
365
366         return -(cd->dseglen);
367 }
368
369
370 static void dseg_addtarget(codegendata *cd, basicblock *target)
371 {
372         jumpref *jr;
373
374         jr = DNEW(jumpref);
375         jr->tablepos = dseg_addaddress(cd, NULL);
376         jr->target = target;
377         jr->next = cd->jumpreferences;
378         cd->jumpreferences = jr;
379 }
380
381
382 static void dseg_adddata(codegendata *cd, u1 *ptr)
383 {
384         dataref *dr;
385
386         dr = DNEW(dataref);
387         dr->pos = (u1 *) (ptr - cd->mcodebase);
388         dr->next = cd->datareferences;
389         cd->datareferences = dr;
390 }
391
392
393 static void dseg_addlinenumbertablesize(codegendata *cd)
394 {
395 #ifdef __ALPHA__
396         dseg_adds4(cd, 0); /*PADDING*/
397 #endif
398         cd->linenumbertablesizepos = dseg_addaddress(cd, NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
399
400         cd->linenumbertablestartpos = dseg_addaddress(cd, NULL);
401 #ifdef __ALPHA__
402         dseg_adds4(cd, 0); /*PADDING*/
403 #endif
404 }
405
406
407 static void dseg_addlinenumber(codegendata *cd, u2 linenumber, u1 *ptr)
408 {
409         linenumberref *lr;
410
411         lr = DNEW(linenumberref);
412         lr->linenumber = linenumber;
413         lr->tablepos = 0;
414         lr->targetmpc = (ptr - cd->mcodebase);
415         lr->next = cd->linenumberreferences;
416         cd->linenumberreferences = lr;
417 }
418
419
420 /* we need this function externally on i386 and x86_64, but keep the call fast
421    on alpha... */
422
423 #if defined(__I386__) || defined(__X86_64__)
424 void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
425 #else
426 static void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
427 #endif
428 {
429         s4 branchpos;
430
431         branchpos = (u1 *) branchptr - cd->mcodebase;
432
433         if (target->mpc >= 0) {
434                 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
435                                                   branchpos,
436                                                   target->mpc);
437
438         } else {
439                 branchref *br = DNEW(branchref);
440
441                 br->branchpos = branchpos;
442                 br->next = target->branchrefs;
443                 target->branchrefs = br;
444         }
445 }
446
447
448 static void codegen_addxboundrefs(codegendata *cd, void *branchptr, s4 reg)
449 {
450         s4 branchpos;
451         branchref *br;
452
453         branchpos = (u1 *) branchptr - cd->mcodebase;
454
455         br = DNEW(branchref);
456         br->branchpos = branchpos;
457         br->reg = reg;
458         br->next = cd->xboundrefs;
459         cd->xboundrefs = br;
460 }
461
462
463 static void codegen_addxcheckarefs(codegendata *cd, void *branchptr)
464 {
465         s4 branchpos;
466         branchref *br;
467
468         branchpos = (u1 *) branchptr - cd->mcodebase;
469
470         br = DNEW(branchref);
471         br->branchpos = branchpos;
472         br->next = cd->xcheckarefs;
473         cd->xcheckarefs = br;
474 }
475
476
477 static void codegen_addxnullrefs(codegendata *cd, void *branchptr)
478 {
479         s4 branchpos;
480         branchref *br;
481
482         branchpos = (u1 *) branchptr - cd->mcodebase;
483
484         br = DNEW(branchref);
485         br->branchpos = branchpos;
486         br->next = cd->xnullrefs;
487         cd->xnullrefs = br;
488 }
489
490
491 static void codegen_addxcastrefs(codegendata *cd, void *branchptr)
492 {
493         s4 branchpos;
494         branchref *br;
495
496         branchpos = (u1 *) branchptr - cd->mcodebase;
497
498         br = DNEW(branchref);
499         br->branchpos = branchpos;
500         br->next = cd->xcastrefs;
501         cd->xcastrefs = br;
502 }
503
504
505 static void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
506 {
507         s4 branchpos;
508         branchref *br;
509
510         branchpos = (u1 *) branchptr - cd->mcodebase;
511
512         br = DNEW(branchref);
513         br->branchpos = branchpos;
514         br->next = cd->xexceptionrefs;
515         cd->xexceptionrefs = br;
516 }
517
518
519 #if defined(__I386__) || defined(__X86_64__)
520 static void codegen_addxdivrefs(codegendata *cd, void *branchptr)
521 {
522         s4 branchpos;
523         branchref *br;
524
525         branchpos = (u1 *) branchptr - cd->mcodebase;
526
527         br = DNEW(branchref);
528         br->branchpos = branchpos;
529         br->next = cd->xdivrefs;
530         cd->xdivrefs = br;
531 }
532 #endif
533
534
535 static void codegen_addclinitref(codegendata *cd,
536                                                                  void *branchptr,
537                                                                  classinfo *class)
538 {
539         s4 branchpos;
540         clinitref *cr;
541
542         branchpos = (u1 *) branchptr - cd->mcodebase;
543
544         cr = DNEW(clinitref);
545         cr->branchpos = branchpos;
546         cr->class = class;
547         cr->next = cd->clinitrefs;
548         cd->clinitrefs = cr;
549 }
550
551
552 static void codegen_createlinenumbertable(codegendata *cd)
553 {
554 #if defined(__I386__) || defined(__ALPHA__)
555         linenumberref *lr;
556
557         for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
558                 lr->tablepos = dseg_addaddress(cd, NULL);
559
560                 if (cd->linenumbertab == 0)
561                         cd->linenumbertab = lr->tablepos;
562
563                 dseg_addaddress(cd, lr->linenumber);
564         }
565 #endif
566 }
567
568
569 #if defined(__I386__) || defined(__X86_64__)
570 static int methodtree_comparator(const void *pc, const void *element, void *param)
571 {
572         methodtree_element *mte;
573         methodtree_element *mtepc;
574
575         mte = (methodtree_element *) element;
576         mtepc = (methodtree_element *) pc;
577
578         /* compare both startpc and endpc of pc, even if they have the same value,
579            otherwise the avl_probe sometimes thinks the element is already in the
580            tree */
581         if ((long) mte->startpc <= (long) mtepc->startpc &&
582                 (long) mtepc->startpc <= (long) mte->endpc &&
583                 (long) mte->startpc <= (long) mtepc->endpc &&
584                 (long) mtepc->endpc <= (long) mte->endpc) {
585                 return 0;
586
587         } else if ((long) mtepc->startpc < (long) mte->startpc) {
588                 return -1;
589
590         } else {
591                 return 1;
592         }
593 }
594
595
596 #if 0
597 void *codegen_findmethod1(void *pc)
598 {
599         void * retVal=findmethod(pc);
600         methodinfo **ma=(methodinfo**)retVal;
601         methodinfo *m=ma[-1];
602         if (m)
603                 if (m->name)
604                         utf_display(m->name);
605                 else 
606                         log_text("No Name");
607         else log_text("No methodinfo");
608         return retVal;
609 }
610 #endif
611
612
613 void codegen_insertmethod(functionptr startpc, functionptr endpc)
614 {
615         methodtree_element *mte;
616
617 #if defined(USE_THREADS)
618 #if defined(NATIVE_THREADS)
619         tables_lock();
620 #endif
621 #endif
622
623         mte = NEW(methodtree_element);
624         mte->startpc = startpc;
625         mte->endpc = endpc;
626
627         if (avl_insert(methodtree, mte)) {
628 #if defined(USE_THREADS)
629 #if defined(NATIVE_THREADS)
630                 tables_unlock();
631 #endif
632 #endif
633                 throw_cacao_exception_exit(string_java_lang_InternalError,
634                                                                    "duplicate entry");
635         }
636
637 #if defined(USE_THREADS)
638 #if defined(NATIVE_THREADS)
639         tables_unlock();
640 #endif
641 #endif
642 }
643
644
645 functionptr codegen_findmethod(functionptr pc)
646 {
647         methodtree_element *mtepc;
648         methodtree_element *mte;
649
650 #if defined(USE_THREADS)
651 #if defined(NATIVE_THREADS)
652         tables_lock();
653 #endif
654 #endif
655
656         mtepc = NEW(methodtree_element);
657         mtepc->startpc = pc;
658         mtepc->endpc = pc;
659
660         mte = avl_find(methodtree, mtepc);
661
662         FREE(mtepc, methodtree_element);
663
664         if (!mte) {
665 #if defined(USE_THREADS)
666 #if defined(NATIVE_THREADS)
667                 tables_unlock();
668 #endif
669 #endif
670                 throw_cacao_exception_exit(string_java_lang_InternalError,
671                                                                    "cannot find function");
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 static void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
726 {
727         jumpref *jr;
728         functionptr epoint;
729         s4 extralen;
730         s4 alignedlen;
731
732 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
733         extralen = sizeof(threadcritnode) * cd->threadcritcount;
734 #else
735         extralen = 0;
736 #endif
737
738 #if defined(STATISTICS)
739         if (opt_stat) {
740                 count_code_len += mcodelen;
741                 count_data_len += cd->dseglen;
742         }
743 #endif
744
745         cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
746         alignedlen = ALIGN(mcodelen, MAX_ALIGN) + cd->dseglen;
747
748         m->mcodelength = mcodelen + cd->dseglen;
749         m->mcode = (functionptr) (long) CNEW(u1, alignedlen + extralen);
750
751         memcpy((void *) (long) m->mcode, cd->dsegtop - cd->dseglen, cd->dseglen);
752         memcpy((void *) ((long) m->mcode + cd->dseglen), cd->mcodebase, mcodelen);
753
754         m->entrypoint = epoint = (functionptr) ((long) m->mcode + cd->dseglen);
755
756         /* jump table resolving */
757         jr = cd->jumpreferences;
758         while (jr != NULL) {
759                 *((functionptr *) ((long) epoint + jr->tablepos)) =
760                         (functionptr) ((long) epoint + (long) jr->target->mpc);
761                 jr = jr->next;
762         }
763
764 #if defined(__I386__) || defined(__ALPHA__)
765         /* line number table resolving */
766         {
767                 linenumberref *lr;
768 #if POINTERSIZE == 8
769                 s8 lrtlen = 0;
770 #else
771                 s4 lrtlen = 0;
772 #endif
773
774                 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
775                         lrtlen++;
776                         *((functionptr *) ((long) epoint + (long) lr->tablepos)) =
777                                 (functionptr) ((long) epoint + (long) lr->targetmpc);
778                 }
779                 
780                 *((functionptr *) ((long) epoint + cd->linenumbertablestartpos)) =
781                         (functionptr) ((long) epoint + cd->linenumbertab);
782 #if POINTERSIZE == 8
783                 *((s8 *) ((s8) epoint + cd->linenumbertablesizepos)) = lrtlen;
784 #else
785                 *((s4 *) ((s4) epoint + cd->linenumbertablesizepos)) = lrtlen;
786 #endif
787         }
788 #endif
789
790 #if defined(__I386__) || defined(__X86_64__)
791         {
792                 dataref *dr;
793
794                 /* add method into methodtree to find the entrypoint */
795                 codegen_insertmethod(m->entrypoint,
796                                                          (functionptr) ((long) m->entrypoint + mcodelen));
797
798                 /* data segment references resolving */
799                 dr = cd->datareferences;
800                 while (dr != NULL) {
801                         *((functionptr *) ((long) epoint + (long) dr->pos - POINTERSIZE)) =
802                                 epoint;
803                         dr = dr->next;
804                 }
805         }
806 #endif
807
808 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
809         {
810                 threadcritnode *n = (threadcritnode *) ((long) m->mcode + alignedlen);
811                 s4 i;
812                 threadcritnodetemp *nt = cd->threadcrit;
813
814                 for (i = 0; i < cd->threadcritcount; i++) {
815                         n->mcodebegin = (u1 *) (long) m->mcode + nt->mcodebegin;
816                         n->mcodeend = (u1 *) (long) m->mcode + nt->mcodeend;
817                         n->mcoderestart = (u1 *) (long) m->mcode + nt->mcoderestart;
818                         thread_registercritical(n);
819                         n++;
820                         nt = nt->next;
821                 }
822         }
823 #endif
824 }
825
826
827 void dseg_display(methodinfo *m, codegendata *cd)
828 {
829         s4 *s4ptr;
830         s4 i;
831         
832         s4ptr = (s4 *) (long) m->mcode;
833
834         printf("  --- dump of datasegment\n");
835         for (i = cd->dseglen; i > 0 ; i -= 4) {
836                 printf("-%6x: %8x\n", i, (s4) (*s4ptr++));
837         }
838         printf("  --- begin of data segment: %p\n", (void *) s4ptr);
839 }
840
841
842 /* reg_of_var:
843     This function determines a register, to which the result of an operation
844     should go, when it is ultimatively intended to store the result in
845     pseudoregister v.
846     If v is assigned to an actual register, this register will be returned.
847     Otherwise (when v is spilled) this function returns tempregnum.
848     If not already done, regoff and flags are set in the stack location.
849 */        
850
851 static int reg_of_var(registerdata *rd, stackptr v, int tempregnum)
852 {
853         varinfo *var;
854
855         switch (v->varkind) {
856         case TEMPVAR:
857                 if (!(v->flags & INMEMORY))
858                         return(v->regoff);
859                 break;
860         case STACKVAR:
861                 var = &(rd->interfaces[v->varnum][v->type]);
862                 v->regoff = var->regoff;
863                 if (!(var->flags & INMEMORY))
864                         return(var->regoff);
865                 break;
866         case LOCALVAR:
867                 var = &(rd->locals[v->varnum][v->type]);
868                 v->regoff = var->regoff;
869                 if (!(var->flags & INMEMORY))
870                         return(var->regoff);
871                 break;
872         case ARGVAR:
873                 v->regoff = v->varnum;
874                 if (IS_FLT_DBL_TYPE(v->type)) {
875                         if (v->varnum < rd->fltreg_argnum) {
876                                 v->regoff = rd->argfltregs[v->varnum];
877                                 return(rd->argfltregs[v->varnum]);
878                         }
879
880                 } else {
881 #if defined(__POWERPC__)
882                         if (v->varnum < rd->intreg_argnum - (IS_2_WORD_TYPE(v->type) != 0)) {
883 #else
884                         if (v->varnum < rd->intreg_argnum) {
885 #endif
886                                 v->regoff = rd->argintregs[v->varnum];
887                                 return (rd->argintregs[v->varnum]);
888                         }
889                 }
890 #if defined(__POWERPC__)
891                 v->regoff += 6;
892 #else
893                 v->regoff -= rd->intreg_argnum;
894 #endif
895                 break;
896         }
897         v->flags |= INMEMORY;
898         return tempregnum;
899 }
900
901
902 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
903 static void codegen_threadcritrestart(codegendata *cd, int offset)
904 {
905         cd->threadcritcurrent.mcoderestart = offset;
906 }
907
908
909 static void codegen_threadcritstart(codegendata *cd, int offset)
910 {
911         cd->threadcritcurrent.mcodebegin = offset;
912 }
913
914
915 static void codegen_threadcritstop(codegendata *cd, int offset)
916 {
917         cd->threadcritcurrent.next = cd->threadcrit;
918         cd->threadcritcurrent.mcodeend = offset;
919         cd->threadcrit = DNEW(threadcritnodetemp);
920         *(cd->threadcrit) = cd->threadcritcurrent;
921         cd->threadcritcount++;
922 }
923 #endif
924
925
926 #ifndef STATIC_CLASSPATH
927 static size_t codegen_overloadPartLen(utf *desc) {
928         char *utf_ptr=desc->text;
929         u2 c;
930         size_t len=2;
931         while ((c=utf_nextu2(&utf_ptr))!=')') {
932                 switch (c) {
933                         case 'I':
934                         case 'S':
935                         case 'B':
936                         case 'C':
937                         case 'Z':
938                         case 'J':
939                         case 'F':
940                         case 'D':
941                                 len ++;
942                                 break;
943                         case '[':
944                                 len = len+2;
945                                 break;
946                         case 'L':
947                                 len++;
948                                 while ( (c=utf_nextu2(&utf_ptr)) != ';')
949                                         len++;
950                                 len=len+2;
951                                 break;
952                         case '(':
953                                 break;
954                         default: panic ("invalid method descriptor");
955                 }
956         }
957         return len;
958
959 }
960
961 static void codegen_fillInOverloadPart(char *target,utf *desc) {
962         char *utf_ptr=desc->text;
963         u2 c;
964         char* insertpos=&target[strlen(target)];
965         *(insertpos++)='_';
966         *(insertpos++)='_';
967         while ((c=utf_nextu2(&utf_ptr))!=')') {
968                 switch (c) {
969                         case 'I':
970                         case 'S':
971                         case 'B':
972                         case 'C':
973                         case 'Z':
974                         case 'J':
975                         case 'F':
976                         case 'D':
977                                 *(insertpos++)=c;
978                                 break;
979                         case '[':
980                                 *(insertpos++)='_';
981                                 *(insertpos++)='3';
982                                 break;
983                         case 'L':
984                                 *(insertpos++)='L';
985                                 while ( (c=utf_nextu2(&utf_ptr)) != ';')
986                                         if ( ((c>='a') && (c<='z'))  ||
987                                                 ((c>='A') && (c<='Z')) ||
988                                                 ((c>='0') && (c<='9')) )
989                                                         *(insertpos++)=c;
990                                         else *(insertpos++)='_';
991                                 *(insertpos++)='_';
992                                 *(insertpos++)='2';
993                                 break;
994                         case '(':
995                                 break;
996                         default: panic ("invalid method descriptor");
997                 }
998         }
999         *insertpos='\0';
1000
1001 }
1002
1003 static void codegen_resolve_native(methodinfo *m,void **insertionPoint,void *jmpTarget,void **jmpPatchTarget) {
1004   char *nativeName, *nativeNameEscape;
1005   size_t nativeLen;
1006   size_t i;
1007         void *lib;
1008         void *sym;
1009
1010   builtin_monitorenter((java_objectheader*) m);
1011 #if defined(__X86_64__)
1012   if ((*((s4*)jmpPatchTarget))==((s4)jmpTarget)) {
1013 #else
1014   if ((*jmpPatchTarget)==jmpTarget) {
1015 #endif
1016     builtin_monitorexit((java_objectheader*) m);
1017     return;
1018   }
1019   /*log_text("trying to resolve a native method");
1020   utf_display(m->class->name);
1021   utf_display(m->name);*/
1022   
1023   lib=dlopen(0,RTLD_NOW | RTLD_GLOBAL); /* open the application execution image */
1024   if (lib) { /* it did work -> good, otherwise fail with error*/
1025     int ok=0;
1026     /*generate the name of the native function in the form Java_package1_package2...._classname_methodname*/
1027     nativeLen=/*Java_*/5+strlen(m->class->name->text)+/*_*/1+strlen(m->name->text)+/*\0*/1;
1028     nativeName=MNEW(char,nativeLen);
1029     sprintf(nativeName,"Java_%s/%s",m->class->name->text,m->name->text);
1030         i=5;
1031     while (i<nativeLen) {
1032                 if (nativeName[i]=='_') { /* escape underscore */
1033                         nativeNameEscape = MNEW(char,nativeLen+1);
1034                         memcpy(nativeNameEscape,nativeName,i+1);
1035                         nativeNameEscape[i+1] = '1'; /* escape sequence for _ is _1 */
1036                         memcpy(&nativeNameEscape[i+2],&nativeName[i+1],nativeLen-i-1);
1037                         MFREE(nativeName,char,nativeLen);
1038                         i++;
1039                         nativeLen++;
1040                         nativeNameEscape[nativeLen]=0;
1041                         nativeName=nativeNameEscape;
1042                 }
1043                 if (nativeName[i]=='/') nativeName[i]='_';
1044                 i++;
1045     } 
1046
1047 /*      printf("nativename: %s\n",nativeName); */
1048
1049     /*try to find the symbal fo the function */
1050     sym=dlsym(lib,nativeName);
1051     if (sym) {
1052       ok=1; /* it worked, everything fine */
1053       /*log_text("resolved");*/
1054       MFREE(nativeName,char,nativeLen);
1055     } else { /* we didn't find the symbol yet, try to resolve an overlaoded function (having the types in it's name*/
1056       size_t overloadedNativeLen=nativeLen+codegen_overloadPartLen(m->descriptor);
1057       char *overloadedNative=MNEW(char,overloadedNativeLen);
1058       sprintf(overloadedNative,"%s",nativeName);
1059       MFREE(nativeName,char,nativeLen);
1060       codegen_fillInOverloadPart(overloadedNative,m->descriptor);
1061       /*log_text("symbol not found,trying harder (overloaded member ?)");*/
1062       sym=dlsym(lib,overloadedNative);
1063       if (sym) {
1064         MFREE(overloadedNative,char,overloadedNativeLen);
1065         ok=1; /* we eventually found the native function -> everything ok*/
1066         /*log_text("resolved");*/
1067       } else { 
1068          /* we failed to find the native function within the execution image (app + loaded libraries) -> will cause an exit*/
1069          MFREE(overloadedNative,char,overloadedNativeLen);
1070          log_text("It was not possible to find the native function implementation. Not even in overloading case");
1071       }
1072    }
1073     /* patch the address of the native function into the stub and make the stub jump over this function call in the future */
1074     if (ok) {
1075       (*insertionPoint)=sym;
1076 #if defined(__X86_64__)
1077       (*((s4*)jmpPatchTarget))=(s4)jmpTarget;
1078 #else
1079       (*jmpPatchTarget)=jmpTarget;
1080 #endif
1081       builtin_monitorexit((java_objectheader *) m );
1082       return;
1083     }
1084
1085   } else log_text("library not found");
1086   
1087   /* There was an error, either the app image could not be opened or the native does not exist in the application and the
1088      loaded libraries. Show an additional error and exit the vm*/
1089   {
1090     char *info;
1091     size_t slen;
1092     slen=2+strlen(m->class->name->text)+strlen(m->name->text)+strlen(m->descriptor->text);
1093     info=(char*)MNEW(char,slen);
1094     sprintf(info,"%s.%s%s",m->class->name->text,m->name->text,m->descriptor->text);
1095     
1096     builtin_monitorexit((java_objectheader *) m );
1097     throw_cacao_exception_exit(string_java_lang_LinkageError,
1098                                                        info);
1099   }
1100   
1101 }
1102 #endif
1103
1104
1105 #endif
1106
1107 /*
1108  * These are local overrides for various environment variables in Emacs.
1109  * Please do not remove this and leave it at the end of the file, where
1110  * Emacs will automagically detect them.
1111  * ---------------------------------------------------------------------
1112  * Local variables:
1113  * mode: c
1114  * indent-tabs-mode: t
1115  * c-basic-offset: 4
1116  * tab-width: 4
1117  * End:
1118  */