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