Reentrant jit compiler changes for powerpc.
[cacao.git] / src / vm / jit / codegen.inc
1 /* jit/codegen.inc - architecture independent code generator
2
3    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4    Institut f. Computersprachen, TU Wien
5    R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Probst,
6    S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich,
7    J. Wenninger
8
9    This file is part of CACAO.
10
11    This program is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public License as
13    published by the Free Software Foundation; either version 2, or (at
14    your option) any later version.
15
16    This program is distributed in the hope that it will be useful, but
17    WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24    02111-1307, USA.
25
26    Contact: cacao@complang.tuwien.ac.at
27
28    Authors: Reinhard Grafl
29             Andreas  Krall
30
31    Changes: Michael Gschwind
32             Christian Thalinger
33
34    All functions assume the following code area / data area layout:
35
36    +-----------+
37    |           |
38    | code area | code area grows to higher addresses
39    |           |
40    +-----------+ <-- start of procedure
41    |           |
42    | data area | data area grows to lower addresses
43    |           |
44    +-----------+
45
46    The functions first write into a temporary code/data area allocated by
47    "codegen_init". "codegen_finish" copies the code and data area into permanent
48    memory. All functions writing values into the data area return the offset
49    relative the begin of the code area (start of procedure).    
50
51    $Id: codegen.inc 1420 2004-10-27 16:05:14Z twisti $
52
53 */
54
55
56 #include <string.h>
57 #include "exceptions.h"
58 #include "native.h"
59 #include "options.h"
60 #include "statistics.h"
61 #include "jit/codegen.inc.h"
62 #include "toolbox/memory.h"
63 #include "toolbox/logging.h"
64 #include "toolbox/avl.h"
65 #include "threads/thread.h"
66
67
68 /* in this tree we store all method addresses */
69
70 #if defined(__I386__) || defined(__X86_64__)
71 static struct avl_table *methodtree = NULL;
72 static int methodtree_comparator(const void *pc, const void *element,
73                                                                  void *param);
74 #endif
75
76
77 /* codegen_init ****************************************************************
78
79    TODO
80
81 *******************************************************************************/
82
83 void codegen_init()
84 {
85 #if defined(__I386__) || defined(__X86_64__)
86         /* this tree is global, not method specific */
87         if (!methodtree) {
88                 methodtree_element *mte;
89
90                 methodtree = avl_create(methodtree_comparator, NULL, NULL);
91
92                 mte = NEW(methodtree_element);
93
94                 mte->startpc = asm_calljavafunction;
95                 mte->endpc = asm_calljavafunction2 - 1;
96
97                 avl_insert(methodtree, mte);
98
99                 mte = NEW(methodtree_element);
100
101                 mte->startpc = asm_calljavafunction2;
102                 mte->endpc = asm_call_jit_compiler - 1;
103
104                 avl_insert(methodtree, mte);
105         }
106 #endif
107 }
108
109
110 /* codegen_setup **************************************************************
111
112    allocates and initialises code area, data area and references
113
114 *******************************************************************************/
115
116 void codegen_setup(methodinfo *m, t_inlining_globals * e)
117 {
118         codegendata *cd;
119
120         m->codegendata = NEW(codegendata);
121
122         /* keep code size smaller */
123         cd = m->codegendata;
124
125         cd->mcodebase = MNEW(u1, MCODEINITSIZE);
126         cd->mcodesize = MCODEINITSIZE;
127         
128         cd->dsegtop = MNEW(u1, DSEGINITSIZE);
129         cd->dsegsize = DSEGINITSIZE;
130         cd->dsegtop += cd->dsegsize;
131         cd->dseglen = 0;
132
133         cd->jumpreferences = NULL;
134         cd->datareferences = NULL;
135         cd->xboundrefs = NULL;
136         cd->xcheckarefs = NULL;
137         cd->xnullrefs = NULL;
138         cd->xcastrefs = NULL;
139         cd->xdivrefs = NULL;
140         cd->xexceptionrefs = NULL;
141
142         cd->linenumberreferences = NULL;
143         cd->linenumbertablesizepos = 0;
144         cd->linenumbertablestartpos = 0;
145         cd->linenumbertab = 0;
146         
147         cd->method=m;
148         cd->exceptiontable=0;
149         cd->exceptiontablelength=0;
150         if (useinlining && e) {
151                 if (e->cumextablelength>0) {
152                         cd->exceptiontablelength=e->cumextablelength;
153                         cd->exceptiontable  = MNEW(exceptiontable, e->cumextablelength + 1);
154                 }
155         } else if (e && (e->method->exceptiontablelength >0)) {
156                         cd->exceptiontablelength=m->exceptiontablelength;
157                         cd->exceptiontable  = MNEW(exceptiontable, m->exceptiontablelength + 1);
158         }
159
160 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
161         cd->threadcritcurrent.next = NULL;
162         cd->threadcritcount = 0;
163 #endif
164 }
165
166
167 /* codegen_close releases temporary code and data area                        */
168
169 void codegen_close(methodinfo *m)
170 {
171         codegendata *cd;
172
173         cd = m->codegendata;
174
175         if (cd) {
176                 if (cd->exceptiontablelength) {
177                         cd->exceptiontablelength=m->exceptiontablelength;
178                         MFREE(cd->exceptiontable, exceptiontable, cd->exceptiontablelength + 1);
179                         cd->exceptiontable=0;
180                         cd->exceptiontablelength=0;
181                 }
182                 if (cd->mcodebase) {
183                         MFREE(cd->mcodebase, u1, cd->mcodesize);
184                         cd->mcodebase = NULL;
185                 }
186
187                 if (cd->dsegtop) {
188                         MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
189                         cd->dsegtop = NULL;
190                 }
191
192                 FREE(m->codegendata, codegendata);
193                 m->codegendata = NULL;
194         }
195 }
196
197
198 /* codegen_increase doubles code area                                         */
199
200 static s4 *codegen_increase(methodinfo *m, u1 *codeptr)
201 {
202         codegendata *cd;
203         long len;
204
205         cd = m->codegendata;
206
207         len = codeptr - cd->mcodebase;
208         cd->mcodebase = MREALLOC(cd->mcodebase,
209                                                          u1,
210                                                          cd->mcodesize,
211                                                          cd->mcodesize * 2);
212         cd->mcodesize *= 2;
213         cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
214
215         return (s4 *) (cd->mcodebase + len);
216 }
217
218
219 /* desg_increase doubles data area                                            */
220
221 static void dseg_increase(methodinfo *m)
222 {
223         codegendata *cd;
224         u1 *newstorage;
225
226         cd = m->codegendata;
227
228         newstorage = MNEW(u1, cd->dsegsize * 2);
229
230         memcpy(newstorage + cd->dsegsize, cd->dsegtop - cd->dsegsize, cd->dsegsize);
231         MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
232
233         cd->dsegtop = newstorage;
234         cd->dsegsize *= 2;
235         cd->dsegtop += cd->dsegsize;
236 }
237
238
239 static s4 dseg_adds4_increase(methodinfo *m, s4 value)
240 {
241         codegendata *cd;
242
243         cd = m->codegendata;
244
245         dseg_increase(m);
246
247         *((s4 *) (cd->dsegtop - cd->dseglen)) = value;
248
249         return -(cd->dseglen);
250 }
251
252
253 static s4 dseg_adds4(methodinfo *m, s4 value)
254 {
255         codegendata *cd;
256         s4 *dataptr;
257
258         cd = m->codegendata;
259
260         cd->dseglen += 4;
261         dataptr = (s4 *) (cd->dsegtop - cd->dseglen);
262
263         if (cd->dseglen > cd->dsegsize)
264                 return dseg_adds4_increase(m, value);
265
266         *dataptr = value;
267
268         return -(cd->dseglen);
269 }
270
271
272 #if !defined(__I386__)
273 static s4 dseg_adds8_increase(methodinfo *m, s8 value)
274 {
275         codegendata *cd;
276
277         cd = m->codegendata;
278
279         dseg_increase(m);
280
281         *((s8 *) (cd->dsegtop - cd->dseglen)) = value;
282
283         return -(cd->dseglen);
284 }
285
286
287 static s4 dseg_adds8(methodinfo *m, s8 value)
288 {
289         codegendata *cd;
290         s8 *dataptr;
291
292         cd = m->codegendata;
293
294         cd->dseglen = ALIGN(cd->dseglen + 8, 8);
295         dataptr = (s8 *) (cd->dsegtop - cd->dseglen);
296
297         if (cd->dseglen > cd->dsegsize)
298                 return dseg_adds8_increase(m, value);
299
300         *dataptr = value;
301
302         return -(cd->dseglen);
303 }
304 #endif
305
306
307 static s4 dseg_addfloat_increase(methodinfo *m, float value)
308 {
309         codegendata *cd;
310
311         cd = m->codegendata;
312
313         dseg_increase(m);
314
315         *((float *) (cd->dsegtop - cd->dseglen)) = value;
316
317         return -(cd->dseglen);
318 }
319
320
321 static s4 dseg_addfloat(methodinfo *m, float value)
322 {
323         codegendata *cd;
324         float *dataptr;
325
326         cd = m->codegendata;
327
328         cd->dseglen += 4;
329         dataptr = (float *) (cd->dsegtop - cd->dseglen);
330
331         if (cd->dseglen > cd->dsegsize)
332                 return dseg_addfloat_increase(m, value);
333
334         *dataptr = value;
335
336         return -(cd->dseglen);
337 }
338
339
340 static s4 dseg_adddouble_increase(methodinfo *m, double value)
341 {
342         codegendata *cd;
343
344         cd = m->codegendata;
345
346         dseg_increase(m);
347
348         *((double *) (cd->dsegtop - cd->dseglen)) = value;
349
350         return -(cd->dseglen);
351 }
352
353
354 static s4 dseg_adddouble(methodinfo *m, double value)
355 {
356         codegendata *cd;
357         double *dataptr;
358
359         cd = m->codegendata;
360
361         cd->dseglen = ALIGN(cd->dseglen + 8, 8);
362         dataptr = (double *) (cd->dsegtop - cd->dseglen);
363
364         if (cd->dseglen > cd->dsegsize)
365                 return dseg_adddouble_increase(m, value);
366
367         *dataptr = value;
368
369         return -(cd->dseglen);
370 }
371
372
373 static void dseg_addtarget(methodinfo *m, basicblock *target)
374 {
375         codegendata *cd;
376         jumpref *jr;
377
378         cd = m->codegendata;
379         
380         jr = DNEW(jumpref);
381         jr->tablepos = dseg_addaddress(m, NULL);
382         jr->target = target;
383         jr->next = cd->jumpreferences;
384         cd->jumpreferences = jr;
385 }
386
387
388 static void dseg_adddata(methodinfo *m, u1 *ptr)
389 {
390         codegendata *cd;
391         dataref *dr;
392
393         cd = m->codegendata;
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(methodinfo *m)
403 {
404         codegendata *cd;
405
406         cd = m->codegendata;
407
408 #ifdef __ALPHA__
409         dseg_adds4(m, 0); /*PADDING*/
410 #endif
411         cd->linenumbertablesizepos = dseg_addaddress(m, NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
412
413         cd->linenumbertablestartpos = dseg_addaddress(m, NULL);
414 #ifdef __ALPHA__
415         dseg_adds4(m, 0); /*PADDING*/
416 #endif
417 }
418
419
420 static void dseg_addlinenumber(methodinfo *m, u2 linenumber, u1 *ptr)
421 {
422         codegendata *cd;
423         linenumberref *lr;
424
425         cd = m->codegendata;
426
427         lr = DNEW(linenumberref);
428         lr->linenumber = linenumber;
429         lr->tablepos = 0;
430         lr->targetmpc = (ptr - cd->mcodebase);
431         lr->next = cd->linenumberreferences;
432         cd->linenumberreferences = lr;
433 }
434
435
436 /* we need this function externally on i386 and x86_64, but keep the call fast
437    on alpha... */
438
439 #if defined(__I386__) || defined(__X86_64__)
440 void codegen_addreference(methodinfo *m, basicblock *target, void *branchptr)
441 #else
442 static void codegen_addreference(methodinfo *m, basicblock *target, void *branchptr)
443 #endif
444 {
445         codegendata *cd;
446         s4 branchpos;
447
448         cd = m->codegendata;
449
450         branchpos = (u1 *) branchptr - cd->mcodebase;
451
452         if (target->mpc >= 0) {
453                 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
454                                                   branchpos,
455                                                   target->mpc);
456
457         } else {
458                 branchref *br = DNEW(branchref);
459
460                 br->branchpos = branchpos;
461                 br->next = target->branchrefs;
462                 target->branchrefs = br;
463         }
464 }
465
466
467 static void codegen_addxboundrefs(methodinfo *m, void *branchptr, s4 reg)
468 {
469         codegendata *cd;
470         s4 branchpos;
471         branchref *br;
472
473         cd = m->codegendata;
474
475         branchpos = (u1 *) branchptr - cd->mcodebase;
476
477         br = DNEW(branchref);
478         br->branchpos = branchpos;
479         br->reg = reg;
480         br->next = cd->xboundrefs;
481         cd->xboundrefs = br;
482 }
483
484
485 static void codegen_addxcheckarefs(methodinfo *m, void *branchptr)
486 {
487         codegendata *cd;
488         s4 branchpos;
489         branchref *br;
490
491         cd = m->codegendata;
492
493         branchpos = (u1 *) branchptr - cd->mcodebase;
494
495         br = DNEW(branchref);
496         br->branchpos = branchpos;
497         br->next = cd->xcheckarefs;
498         cd->xcheckarefs = br;
499 }
500
501
502 static void codegen_addxnullrefs(methodinfo *m, void *branchptr)
503 {
504         codegendata *cd;
505         s4 branchpos;
506         branchref *br;
507
508         cd = m->codegendata;
509
510         branchpos = (u1 *) branchptr - cd->mcodebase;
511
512         br = DNEW(branchref);
513         br->branchpos = branchpos;
514         br->next = cd->xnullrefs;
515         cd->xnullrefs = br;
516 }
517
518
519
520 static void codegen_addxcastrefs(methodinfo *m, void *branchptr)
521 {
522         codegendata *cd;
523         s4 branchpos;
524         branchref *br;
525
526         cd = m->codegendata;
527
528         branchpos = (u1 *) branchptr - cd->mcodebase;
529
530         br = DNEW(branchref);
531         br->branchpos = branchpos;
532         br->next = cd->xcastrefs;
533         cd->xcastrefs = br;
534 }
535
536
537 static void codegen_addxexceptionrefs(methodinfo *m, void *branchptr)
538 {
539         codegendata *cd;
540         s4 branchpos;
541         branchref *br;
542
543         cd = m->codegendata;
544
545         branchpos = (u1 *) branchptr - cd->mcodebase;
546
547         br = DNEW(branchref);
548         br->branchpos = branchpos;
549         br->next = cd->xexceptionrefs;
550         cd->xexceptionrefs = br;
551 }
552
553
554 #if defined(__I386__) || defined(__X86_64__)
555 static void codegen_addxdivrefs(methodinfo *m, void *branchptr)
556 {
557         codegendata *cd;
558         s4 branchpos;
559         branchref *br;
560
561         cd = m->codegendata;
562
563         branchpos = (u1 *) branchptr - cd->mcodebase;
564
565         br = DNEW(branchref);
566         br->branchpos = branchpos;
567         br->next = cd->xdivrefs;
568         cd->xdivrefs = br;
569 }
570 #endif
571
572
573 static void codegen_createlinenumbertable(methodinfo *m)
574 {
575 #ifdef __I386__
576         codegendata *cd;
577         linenumberref *lr;
578
579         cd = m->codegendata;
580
581         for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
582                 lr->tablepos = dseg_addaddress(m, NULL);
583
584                 if (cd->linenumbertab == 0)
585                         cd->linenumbertab = lr->tablepos;
586
587                 dseg_addaddress(m, lr->linenumber);
588         }
589 #endif
590 }
591
592
593 #if defined(__I386__) || defined(__X86_64__)
594 static int methodtree_comparator(const void *pc, const void *element, void *param)
595 {
596         methodtree_element *mte;
597         methodtree_element *mtepc;
598
599         mte = (methodtree_element *) element;
600         mtepc = (methodtree_element *) pc;
601
602         /* compare both startpc and endpc of pc, even if they have the same value,
603            otherwise the avl_probe sometimes thinks the element is already in the
604            tree */
605         if (mte->startpc <= mtepc->startpc && mtepc->startpc <= mte->endpc &&
606                 mte->startpc <= mtepc->endpc   && mtepc->endpc   <= mte->endpc) {
607                 return 0;
608
609         } else if (mtepc->startpc < mte->startpc) {
610                 return -1;
611
612         } else {
613                 return 1;
614         }
615 }
616
617
618 #if 0
619 void *codegen_findmethod1(void *pc)
620 {
621         void * retVal=findmethod(pc);
622         methodinfo **ma=(methodinfo**)retVal;
623         methodinfo *m=ma[-1];
624         if (m)
625                 if (m->name)
626                         utf_display(m->name);
627                 else 
628                         log_text("No Name");
629         else log_text("No methodinfo");
630         return retVal;
631 }
632 #endif
633
634
635 void codegen_insertmethod(void *startpc, void *endpc)
636 {
637         methodtree_element *mte;
638
639 #if defined(USE_THREADS)
640 #if defined(NATIVE_THREADS)
641         tables_lock();
642 #endif
643 #endif
644
645         mte = NEW(methodtree_element);
646         mte->startpc = startpc;
647         mte->endpc = endpc;
648
649         if (avl_insert(methodtree, mte)) {
650 #if defined(USE_THREADS)
651 #if defined(NATIVE_THREADS)
652                 tables_unlock();
653 #endif
654 #endif
655                 throw_cacao_exception_exit(string_java_lang_InternalError,
656                                                                    "duplicate entry");
657         }
658
659 #if defined(USE_THREADS)
660 #if defined(NATIVE_THREADS)
661         tables_unlock();
662 #endif
663 #endif
664 }
665
666
667 void *codegen_findmethod(void *pc)
668 {
669         methodtree_element *mtepc;
670         methodtree_element *mte;
671
672         mtepc = NEW(methodtree_element);
673         mtepc->startpc = pc;
674         mtepc->endpc = pc;
675
676         mte = avl_find(methodtree, mtepc);
677
678         FREE(mtepc, methodtree_element);
679
680         if (!mte)
681                 throw_cacao_exception_exit(string_java_lang_InternalError,
682                                                                    "cannot find function");
683
684         return mte->startpc;
685 }
686 #endif
687
688
689 static void codegen_finish(methodinfo *m, s4 mcodelen)
690 {
691         codegendata *cd;
692         jumpref *jr;
693         u1 *epoint;
694         s4 extralen = 0;
695         s4 alignedlen;
696
697         cd = m->codegendata;
698
699 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
700         extralen += sizeof(threadcritnode) * cd->threadcritcount;
701 #endif
702
703 #if defined(STATISTICS)
704         if (opt_stat) {
705                 count_code_len += mcodelen;
706                 count_data_len += cd->dseglen;
707         }
708 #endif
709
710         cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
711         alignedlen = ALIGN(mcodelen, MAX_ALIGN) + cd->dseglen;
712
713         m->mcodelength = mcodelen + cd->dseglen;
714         m->mcode = CNEW(u1, alignedlen + extralen);
715
716         memcpy(m->mcode, cd->dsegtop - cd->dseglen, cd->dseglen);
717         memcpy(m->mcode + cd->dseglen, cd->mcodebase, mcodelen);
718
719         m->entrypoint = epoint = (u1 *) (m->mcode + cd->dseglen);
720
721         /* jump table resolving */
722         jr = cd->jumpreferences;
723         while (jr != NULL) {
724             *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
725             jr = jr->next;
726         }
727
728 #ifdef __I386__
729         /* line number table resolving */
730         {
731                 linenumberref *lr;
732 #if POINTERSIZE == 8
733                 s8 lrtlen = 0;
734 #else
735                 s4 lrtlen = 0;
736 #endif
737
738                 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
739                         lrtlen++;
740                         *((void**) (epoint + lr->tablepos)) = epoint + lr->targetmpc;
741                 }
742                 
743                 *((void**) (epoint + cd->linenumbertablestartpos)) =
744                         epoint + cd->linenumbertab;
745 #if POINTERSIZE == 8
746                 *((s8*) (epoint + cd->linenumbertablesizepos)) = lrtlen;
747 #else
748                 *((s4*) (epoint + cd->linenumbertablesizepos)) = lrtlen;
749 #endif
750         }
751 #endif
752
753 #if defined(__I386__) || defined(__X86_64__)
754         {
755                 dataref *dr;
756
757                 /* add method into methodtree to find the entrypoint */
758                 codegen_insertmethod(m->entrypoint, m->entrypoint + mcodelen);
759
760                 /* data segment references resolving */
761                 dr = cd->datareferences;
762                 while (dr != NULL) {
763                         *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
764                         dr = dr->next;
765                 }
766         }
767 #endif
768
769 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
770         {
771                 threadcritnode *n = (threadcritnode *) (m->mcode + alignedlen);
772                 s4 i;
773                 threadcritnodetemp *nt = cd->threadcrit;
774
775                 for (i = 0; i < cd->threadcritcount; i++) {
776                         n->mcodebegin = m->mcode + nt->mcodebegin;
777                         n->mcodeend = m->mcode + nt->mcodeend;
778                         n->mcoderestart = m->mcode + nt->mcoderestart;
779                         thread_registercritical(n);
780                         n++;
781                         nt = nt->next;
782                 }
783         }
784 #endif
785 }
786
787
788 void dseg_display(methodinfo *m)
789 {
790         s4 *s4ptr;
791         s4 i;
792         
793         s4ptr = (s4 *) m->mcode;
794
795         printf("  --- dump of datasegment\n");
796         for (i = m->codegendata->dseglen; i > 0 ; i -= 4) {
797                 printf("-%6x: %8x\n", i, (s4) (*s4ptr++));
798         }
799         printf("  --- begin of data segment: %p\n", s4ptr);
800 }
801
802
803 #if !defined(__POWERPC__)
804 /* reg_of_var:
805     This function determines a register, to which the result of an operation
806     should go, when it is ultimatively intended to store the result in
807     pseudoregister v.
808     If v is assigned to an actual register, this register will be returned.
809     Otherwise (when v is spilled) this function returns tempregnum.
810     If not already done, regoff and flags are set in the stack location.
811 */        
812
813 static int reg_of_var(methodinfo *m, stackptr v, int tempregnum)
814 {
815         varinfo *var;
816
817         switch (v->varkind) {
818         case TEMPVAR:
819                 if (!(v->flags & INMEMORY))
820                         return(v->regoff);
821                 break;
822         case STACKVAR:
823                 var = &(m->registerdata->interfaces[v->varnum][v->type]);
824                 v->regoff = var->regoff;
825                 if (!(var->flags & INMEMORY))
826                         return(var->regoff);
827                 break;
828         case LOCALVAR:
829                 var = &(m->registerdata->locals[v->varnum][v->type]);
830                 v->regoff = var->regoff;
831                 if (!(var->flags & INMEMORY))
832                         return(var->regoff);
833                 break;
834         case ARGVAR:
835                 v->regoff = v->varnum;
836                 if (IS_FLT_DBL_TYPE(v->type)) {
837                         if (v->varnum < m->registerdata->fltreg_argnum) {
838                                 v->regoff = m->registerdata->argfltregs[v->varnum];
839                                 return(m->registerdata->argfltregs[v->varnum]);
840                         }
841                 }
842                 else
843                         if (v->varnum < m->registerdata->intreg_argnum) {
844                                 v->regoff = m->registerdata->argintregs[v->varnum];
845                                 return(m->registerdata->argintregs[v->varnum]);
846                         }
847                 v->regoff -= m->registerdata->intreg_argnum;
848                 break;
849         }
850         v->flags |= INMEMORY;
851         return tempregnum;
852 }
853 #endif
854
855
856 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
857 static void codegen_threadcritrestart(methodinfo *m, int offset)
858 {
859         m->codegendata->threadcritcurrent.mcoderestart = offset;
860 }
861
862 static void codegen_threadcritstart(methodinfo *m, int offset)
863 {
864         m->codegendata->threadcritcurrent.mcodebegin = offset;
865 }
866
867 static void codegen_threadcritstop(methodinfo *m, int offset)
868 {
869         codegendata *cd;
870
871         cd = m->codegendata;
872
873         cd->threadcritcurrent.next = cd->threadcrit;
874         cd->threadcritcurrent.mcodeend = offset;
875         cd->threadcrit = DNEW(threadcritnodetemp);
876         *(cd->threadcrit) = cd->threadcritcurrent;
877         cd->threadcritcount++;
878 }
879 #endif
880
881 /*
882  * These are local overrides for various environment variables in Emacs.
883  * Please do not remove this and leave it at the end of the file, where
884  * Emacs will automagically detect them.
885  * ---------------------------------------------------------------------
886  * Local variables:
887  * mode: c
888  * indent-tabs-mode: t
889  * c-basic-offset: 4
890  * tab-width: 4
891  * End:
892  */