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