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