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