GNU header update.
[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 1735 2004-12-07 14:33:27Z 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         case STACKVAR:
860                 var = &(rd->interfaces[v->varnum][v->type]);
861                 v->regoff = var->regoff;
862                 if (!(var->flags & INMEMORY))
863                         return(var->regoff);
864                 break;
865         case LOCALVAR:
866                 var = &(rd->locals[v->varnum][v->type]);
867                 v->regoff = var->regoff;
868                 if (!(var->flags & INMEMORY))
869                         return(var->regoff);
870                 break;
871         case ARGVAR:
872                 v->regoff = v->varnum;
873                 if (IS_FLT_DBL_TYPE(v->type)) {
874                         if (v->varnum < rd->fltreg_argnum) {
875                                 v->regoff = rd->argfltregs[v->varnum];
876                                 return(rd->argfltregs[v->varnum]);
877                         }
878
879                 } else {
880 #if defined(__POWERPC__)
881                         if (v->varnum < rd->intreg_argnum - (IS_2_WORD_TYPE(v->type) != 0)) {
882 #else
883                         if (v->varnum < rd->intreg_argnum) {
884 #endif
885                                 v->regoff = rd->argintregs[v->varnum];
886                                 return (rd->argintregs[v->varnum]);
887                         }
888                 }
889 #if defined(__POWERPC__)
890                 v->regoff += 6;
891 #else
892                 v->regoff -= rd->intreg_argnum;
893 #endif
894                 break;
895         }
896         v->flags |= INMEMORY;
897         return tempregnum;
898 }
899
900
901 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
902 static void codegen_threadcritrestart(codegendata *cd, int offset)
903 {
904         cd->threadcritcurrent.mcoderestart = offset;
905 }
906
907
908 static void codegen_threadcritstart(codegendata *cd, int offset)
909 {
910         cd->threadcritcurrent.mcodebegin = offset;
911 }
912
913
914 static void codegen_threadcritstop(codegendata *cd, int offset)
915 {
916         cd->threadcritcurrent.next = cd->threadcrit;
917         cd->threadcritcurrent.mcodeend = offset;
918         cd->threadcrit = DNEW(threadcritnodetemp);
919         *(cd->threadcrit) = cd->threadcritcurrent;
920         cd->threadcritcount++;
921 }
922 #endif
923
924
925 #ifndef STATIC_CLASSPATH
926 static size_t codegen_overloadPartLen(utf *desc) {
927         char *utf_ptr=desc->text;
928         u2 c;
929         size_t len=2;
930         while ((c=utf_nextu2(&utf_ptr))!=')') {
931                 switch (c) {
932                         case 'I':
933                         case 'S':
934                         case 'B':
935                         case 'C':
936                         case 'Z':
937                         case 'J':
938                         case 'F':
939                         case 'D':
940                                 len ++;
941                                 break;
942                         case '[':
943                                 len = len+2;
944                                 break;
945                         case 'L':
946                                 len++;
947                                 while ( (c=utf_nextu2(&utf_ptr)) != ';')
948                                         len++;
949                                 len=len+2;
950                                 break;
951                         case '(':
952                                 break;
953                         default: panic ("invalid method descriptor");
954                 }
955         }
956         return len;
957
958 }
959
960 static void codegen_fillInOverloadPart(char *target,utf *desc) {
961         char *utf_ptr=desc->text;
962         u2 c;
963         char* insertpos=&target[strlen(target)];
964         *(insertpos++)='_';
965         *(insertpos++)='_';
966         while ((c=utf_nextu2(&utf_ptr))!=')') {
967                 switch (c) {
968                         case 'I':
969                         case 'S':
970                         case 'B':
971                         case 'C':
972                         case 'Z':
973                         case 'J':
974                         case 'F':
975                         case 'D':
976                                 *(insertpos++)=c;
977                                 break;
978                         case '[':
979                                 *(insertpos++)='_';
980                                 *(insertpos++)='3';
981                                 break;
982                         case 'L':
983                                 *(insertpos++)='L';
984                                 while ( (c=utf_nextu2(&utf_ptr)) != ';')
985                                         if ( ((c>='a') && (c<='z'))  ||
986                                                 ((c>='A') && (c<='Z')) ||
987                                                 ((c>='0') && (c<='9')) )
988                                                         *(insertpos++)=c;
989                                         else *(insertpos++)='_';
990                                 *(insertpos++)='_';
991                                 *(insertpos++)='2';
992                                 break;
993                         case '(':
994                                 break;
995                         default: panic ("invalid method descriptor");
996                 }
997         }
998         *insertpos='\0';
999
1000 }
1001
1002 static void codegen_resolve_native(methodinfo *m,void **insertionPoint,void *jmpTarget,void **jmpPatchTarget) {
1003   char *nativeName, *nativeNameEscape;
1004   size_t nativeLen;
1005   size_t i;
1006         void *lib;
1007         void *sym;
1008
1009   builtin_monitorenter((java_objectheader*) m);
1010 #if defined(__X86_64__)
1011   if ((*((s4*)jmpPatchTarget))==((s4)jmpTarget)) {
1012 #else
1013   if ((*jmpPatchTarget)==jmpTarget) {
1014 #endif
1015     builtin_monitorexit((java_objectheader*) m);
1016     return;
1017   }
1018   /*log_text("trying to resolve a native method");
1019   utf_display(m->class->name);
1020   utf_display(m->name);*/
1021   
1022   lib=dlopen(0,RTLD_NOW | RTLD_GLOBAL); /* open the application execution image */
1023   if (lib) { /* it did work -> good, otherwise fail with error*/
1024     int ok=0;
1025     /*generate the name of the native function in the form Java_package1_package2...._classname_methodname*/
1026     nativeLen=/*Java_*/5+strlen(m->class->name->text)+/*_*/1+strlen(m->name->text)+/*\0*/1;
1027     nativeName=MNEW(char,nativeLen);
1028     sprintf(nativeName,"Java_%s/%s",m->class->name->text,m->name->text);
1029         i=5;
1030     while (i<nativeLen) {
1031                 if (nativeName[i]=='_') { /* escape underscore */
1032                         nativeNameEscape = MNEW(char,nativeLen+1);
1033                         memcpy(nativeNameEscape,nativeName,i+1);
1034                         nativeNameEscape[i+1] = '1'; /* escape sequence for _ is _1 */
1035                         memcpy(&nativeNameEscape[i+2],&nativeName[i+1],nativeLen-i-1);
1036                         MFREE(nativeName,char,nativeLen);
1037                         i++;
1038                         nativeLen++;
1039                         nativeNameEscape[nativeLen]=0;
1040                         nativeName=nativeNameEscape;
1041                 }
1042                 if (nativeName[i]=='/') nativeName[i]='_';
1043                 i++;
1044     } 
1045
1046 /*      printf("nativename: %s\n",nativeName); */
1047
1048     /*try to find the symbal fo the function */
1049     sym=dlsym(lib,nativeName);
1050     if (sym) {
1051       ok=1; /* it worked, everything fine */
1052       /*log_text("resolved");*/
1053       MFREE(nativeName,char,nativeLen);
1054     } else { /* we didn't find the symbol yet, try to resolve an overlaoded function (having the types in it's name*/
1055       size_t overloadedNativeLen=nativeLen+codegen_overloadPartLen(m->descriptor);
1056       char *overloadedNative=MNEW(char,overloadedNativeLen);
1057       sprintf(overloadedNative,"%s",nativeName);
1058       MFREE(nativeName,char,nativeLen);
1059       codegen_fillInOverloadPart(overloadedNative,m->descriptor);
1060       /*log_text("symbol not found,trying harder (overloaded member ?)");*/
1061       sym=dlsym(lib,overloadedNative);
1062       if (sym) {
1063         MFREE(overloadedNative,char,overloadedNativeLen);
1064         ok=1; /* we eventually found the native function -> everything ok*/
1065         /*log_text("resolved");*/
1066       } else { 
1067          /* we failed to find the native function within the execution image (app + loaded libraries) -> will cause an exit*/
1068          MFREE(overloadedNative,char,overloadedNativeLen);
1069          log_text("It was not possible to find the native function implementation. Not even in overloading case");
1070       }
1071    }
1072     /* patch the address of the native function into the stub and make the stub jump over this function call in the future */
1073     if (ok) {
1074       (*insertionPoint)=sym;
1075 #if defined(__X86_64__)
1076       (*((s4*)jmpPatchTarget))=(s4)jmpTarget;
1077 #else
1078       (*jmpPatchTarget)=jmpTarget;
1079 #endif
1080       builtin_monitorexit((java_objectheader *) m );
1081       return;
1082     }
1083
1084   } else log_text("library not found");
1085   
1086   /* There was an error, either the app image could not be opened or the native does not exist in the application and the
1087      loaded libraries. Show an additional error and exit the vm*/
1088   {
1089     char *info;
1090     size_t slen;
1091     slen=2+strlen(m->class->name->text)+strlen(m->name->text)+strlen(m->descriptor->text);
1092     info=(char*)MNEW(char,slen);
1093     sprintf(info,"%s.%s%s",m->class->name->text,m->name->text,m->descriptor->text);
1094     
1095     builtin_monitorexit((java_objectheader *) m );
1096     throw_cacao_exception_exit(string_java_lang_LinkageError,
1097                                                        info);
1098   }
1099   
1100 }
1101 #endif
1102
1103
1104 #endif
1105
1106 /*
1107  * These are local overrides for various environment variables in Emacs.
1108  * Please do not remove this and leave it at the end of the file, where
1109  * Emacs will automagically detect them.
1110  * ---------------------------------------------------------------------
1111  * Local variables:
1112  * mode: c
1113  * indent-tabs-mode: t
1114  * c-basic-offset: 4
1115  * tab-width: 4
1116  * End:
1117  */