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