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