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