GC now works without threads being initialized, which caused a
[cacao.git] / src / vm / tables.c
1 /* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */
2 /****************************** tables.c ***************************************
3
4         Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst
5
6         See file COPYRIGHT for information on usage and disclaimer of warranties
7
8         Enth"alt Supportfunktionen f"ur:
9                 - Lesen von JavaClass-Files
10             - unicode-Symbole
11                 - den Heap 
12                 - zus"atzliche Support-Funktionen
13
14         Authors: Reinhard Grafl      EMAIL: cacao@complang.tuwien.ac.at
15         Changes: Mark Probst         EMAIL: cacao@complang.tuwien.ac.at
16                  Andreas  Krall      EMAIL: cacao@complang.tuwien.ac.at
17
18         Last Change: 1998/03/24
19
20 *******************************************************************************/
21
22 #include <assert.h>
23 #include <sys/mman.h>
24 #include <unistd.h>
25 #include "global.h"
26 #include "tables.h"
27 #include "asmpart.h"
28 #include "callargs.h"
29
30 #include "sysdep/threads.h"
31 #include "threads/thread.h"                  /* schani */
32 #include "threads/locks.h"
33
34
35 bool runverbose = false;
36
37 int count_unicode_len = 0;
38
39
40 /******************************************************************************
41 ************************* Der Dateien-Sauger **********************************
42 *******************************************************************************
43
44         dient zum Behandeln von Java-ClassFiles ("offnen, schlie"sen, 
45         einlesen von 8-, 16-, 32-, 64-bit Integers und 32-, 64- bit Floats)
46
47 ******************************************************************************/
48
49 static FILE *classfile = NULL;   /* File-handle der gerade gelesenen Datei */
50 static char *classpath = "";     /* Suchpfad f"ur die ClassFiles */
51
52
53
54 /************************** Funktion: suck_init ******************************
55
56         Wird zu Programmstart einmal aufgerufen und setzt den Suchpfad f"ur
57         Klassenfiles
58
59 ******************************************************************************/
60
61 void suck_init (char *cpath)
62 {
63         classfile = NULL;
64         classpath = cpath;
65 }
66
67
68 /************************** Funktion: suck_start ******************************
69
70         "Offnet die Datei f"ur die Klasse des gegebenen Namens zum Lesen.
71         Dabei werden alle im Suchpfad angegebenen Verzeichnisse durchsucht,
72         bis eine entsprechende Datei  ( <classname>.class) gefunden wird. 
73         
74 ******************************************************************************/
75
76 bool suck_start (unicode *classname)
77 {
78 #define MAXFILENAME 1000           /* Maximale Langes des Dateinamens plus Pfad */
79
80         char filename[MAXFILENAME+10];   /* Platz fuer '.class' */
81         u2 filenamelen;
82         char *pathpos;
83         u2 i,c;
84
85
86         pathpos = classpath;
87
88         while (*pathpos) {
89                 while ( *pathpos == ':' ) pathpos++;
90  
91                 filenamelen=0;
92                 while ( (*pathpos) && (*pathpos!=':') ) {
93                     PANICIF (filenamelen >= MAXFILENAME, "Filename too long") ;
94                         
95                         filename[filenamelen++] = *(pathpos++);
96                         }
97
98                 filename[filenamelen++] = '/';
99    
100                 for (i=0; i < classname -> length; i++) {
101                         PANICIF (filenamelen >= MAXFILENAME, "Filename too long");
102                         
103                         c = classname -> text [i];
104                         if (c=='/') c = '/';     /* Slashes im Namen passen zu UNIX */
105                         else {
106                                 if ( c<=' ' || c>'z') {
107                                         c = '?';
108                                         }
109                                 }
110                         
111                         filename[filenamelen++] = c;    
112                         }
113       
114                 strcpy (filename+filenamelen, ".class");
115
116                 classfile = fopen(filename, "r");
117                 if (classfile) {
118                         return true;
119                         }
120
121                 
122                 }
123                    
124         sprintf (logtext,"Can not open class file '%s'", filename);
125         error();
126         return false;
127 }
128
129
130 /************************** Funktion: suck_stop *******************************
131
132         Schlie"st die offene Datei wieder.
133         
134 ******************************************************************************/
135
136 void suck_stop ()
137 {
138         u4 rest=0;
139         u1 dummy;
140         
141         while ( fread (&dummy, 1,1, classfile) > 0) rest++;
142         if (rest) {
143                 sprintf (logtext,"There are %d access bytes at end of classfile",
144                                  (int) rest);
145                 dolog();
146                 }
147                         
148         fclose (classfile);
149         classfile = NULL;
150 }
151       
152
153
154 /************************** Lesefunktionen ***********************************
155
156         Lesen von der Datei in verschieden grossen Paketen
157         (8,16,32,64-bit Integer oder Float)
158
159 *****************************************************************************/
160
161 void suck_nbytes (u1 *buffer, u4 len)
162 {
163         if ( fread (buffer, 1, len, classfile) != len) panic ("Unexpected EOF");
164 }
165
166
167 void skip_nbytes (u4 len)
168 {
169         u4 i;
170         for (i=0; i<len; i++) suck_u1 ();
171 }
172
173
174 u1 suck_u1 ()
175 {
176         u1 b;
177         if ( fread (&b, 1,1, classfile) != 1) panic ("Unexpected EOF");
178         return b;
179 }
180
181 s1 suck_s1 ()
182 {
183         s1 b;
184         if ( fread (&b, 1,1, classfile) != 1) panic ("Unexpected EOF");
185         return b;
186 }
187
188
189 u2 suck_u2 ()
190 {
191         u1 b[2];
192         if ( fread (b, 1,2, classfile) != 2) panic ("Unexpected EOF");
193         return (b[0]<<8) + b[1];
194 }
195
196 s2 suck_s2 ()
197 {
198         return suck_u2 ();
199 }
200
201
202 u4 suck_u4 ()
203 {
204         u1 b[4];
205         u4 v;
206         if ( fread (b, 1,4, classfile) != 4) panic ("Unexpected EOF");
207         v = ( ((u4)b[0]) <<24) + ( ((u4)b[1])<<16) + ( ((u4)b[2])<<8) + ((u4)b[3]);
208         return v;
209 }
210
211 s4 suck_s4 ()
212 {
213         s4 v = suck_u4 ();
214         return v;
215 }
216
217 u8 suck_u8 ()
218 {
219 #if U8_AVAILABLE
220         u8 lo,hi;
221         hi = suck_u4();
222         lo = suck_u4();
223         return (hi<<32) + lo;
224 #else
225         u8 v;
226         v.high = suck_u4();
227         v.low = suck_u4();
228         return v;
229 #endif
230 }
231
232 s8 suck_s8 ()
233 {
234         return suck_u8 ();
235 }
236         
237
238 float suck_float ()
239 {
240         float f;
241
242 #if !WORDS_BIGENDIAN 
243                 u1 buffer[4];
244                 u2 i;
245                 for (i=0; i<4; i++) buffer[3-i] = suck_u1 ();
246                 memcpy ( (u1*) (&f), buffer, 4);
247 #else 
248                 suck_nbytes ( (u1*) (&f), 4 );
249 #endif
250
251         PANICIF (sizeof(float) != 4, "Incompatible float-format");
252         
253         return f;
254 }
255
256
257 double suck_double ()
258 {
259         double d;
260
261 #if !WORDS_BIGENDIAN 
262                 u1 buffer[8];
263                 u2 i;   
264                 for (i=0; i<8; i++) buffer[7-i] = suck_u1 ();
265                 memcpy ( (u1*) (&d), buffer, 8);
266 #else 
267                 suck_nbytes ( (u1*) (&d), 8 );
268 #endif
269
270         PANICIF (sizeof(double) != 8, "Incompatible double-format" );
271         
272         return d;
273 }
274
275
276
277
278 /******************************************************************************
279 ******************** Der Unicode-Symbol-Verwalter *****************************
280 *******************************************************************************
281
282         legt eine Hashtabelle f"ur unicode-Symbole an und verwaltet
283         das Eintragen neuer Symbole
284         
285 ******************************************************************************/
286
287
288
289 #define UNICODESTART  2187      /* Startgr"osse: moeglichst gross und prim */
290
291 static u4 unicodeentries;       /* Anzahl der Eintr"age in der Tabelle */
292 static u4 unicodehashsize;      /* Gr"osse der Tabelle */
293 static unicode ** unicodehash;  /* Zeiger auf die Tabelle selbst */
294
295
296 /*********************** Funktion: unicode_init ******************************
297
298         Initialisiert die unicode-Symboltabelle (muss zu Systemstart einmal
299         aufgerufen werden)
300         
301 *****************************************************************************/
302
303 void unicode_init ()
304 {
305         u4 i;
306         
307 #ifdef STATISTICS
308         count_unicode_len += sizeof(unicode*) * unicodehashsize;
309 #endif
310
311         unicodeentries = 0;
312         unicodehashsize = UNICODESTART;
313         unicodehash = MNEW (unicode*, unicodehashsize);
314         for (i=0; i<unicodehashsize; i++) unicodehash[i] = NULL;
315 }
316
317
318 /*********************** Funktion: unicode_close *****************************
319
320         Gibt allen Speicher der Symboltabellen frei.
321         Parameter: Ein Zeiger auf eine Funktion, die dazu n"otig ist, 
322                    Stringkonstanten (die mit 'unicode_setstringlink' 
323                    Unicode-Symbole gebunden wurden) wieder freizugeben
324         
325 *****************************************************************************/
326
327 void unicode_close (stringdeleter del)
328 {
329         unicode *u;
330         u4 i;
331         
332         for (i=0; i<unicodehashsize; i++) {
333                 u = unicodehash[i];
334                 while (u) {
335                         unicode *nextu = u->hashlink;
336
337                         if (u->string) del (u->string);
338                         
339                         MFREE (u->text, u2, u->length);
340                         FREE (u, unicode);
341                         u = nextu;
342                         }       
343                 }
344         MFREE (unicodehash, unicode*, unicodehashsize);
345 }
346
347
348 /********************* Funktion: unicode_display ******************************
349         
350         Gibt ein unicode-Symbol auf stdout aus (zu Debugzwecken)
351
352 ******************************************************************************/
353
354 void unicode_display (unicode *u)
355 {
356         u2 i,c;
357         for (i=0; i < u->length; i++) {
358                 c = u->text[i];
359                 if (c>=32 && c<=127) printf ("%c",c);
360                                 else printf ("?");
361                 }
362         fflush (stdout);
363 }
364
365
366 /********************* Funktion: unicode_sprint ******************************
367         
368         Schreibt ein unicode-Symbol in einen C-String
369
370 ******************************************************************************/ 
371
372 void unicode_sprint (char *buffer, unicode *u)
373 {
374         u2 i;
375         for (i=0; i < u->length; i++) buffer[i] = u->text[i];
376         buffer[i] = '\0';
377 }
378
379
380 /********************* Funktion: unicode_fprint ******************************
381         
382         Schreibt ein unicode-Symbol auf eine Datei aus
383
384 ******************************************************************************/ 
385
386 void unicode_fprint (FILE *file, unicode *u)
387 {
388         u2 i;
389         for (i=0; i < u->length; i++) putc (u->text[i], file);
390
391
392
393 /****************** interne Funktion: u_hashkey ******************************/
394
395 static u4 u_hashkey (u2 *text, u2 length)
396 {
397         u4 k = 0;
398         u2 i,sh=0;
399         
400         for (i=0; i<length; i++) {
401                 k ^=  ( ((u4) (text[i])) << sh );
402                 if (sh<16) sh++;
403                      else  sh=0;
404                 }
405                 
406         return k;
407 }
408
409 /*************** interne Funktion: u_reorganizehash **************************/
410
411 static void u_reorganizehash ()
412 {
413         u4 i;
414         unicode *u;
415
416         u4 newhashsize = unicodehashsize*2;
417         unicode **newhash = MNEW (unicode*, newhashsize);
418
419 #ifdef STATISTICS
420         count_unicode_len += sizeof(unicode*) * unicodehashsize;
421 #endif
422
423         for (i=0; i<newhashsize; i++) newhash[i] = NULL;
424
425         for (i=0; i<unicodehashsize; i++) {
426                 u = unicodehash[i];
427                 while (u) {
428                         unicode *nextu = u -> hashlink;
429                         u4 slot = (u->key) % newhashsize;
430                                                 
431                         u->hashlink = newhash[slot];
432                         newhash[slot] = u;
433
434                         u = nextu;
435                         }
436                 }
437         
438         MFREE (unicodehash, unicode*, unicodehashsize);
439         unicodehash = newhash;
440         unicodehashsize = newhashsize;
441 }
442
443
444 /****************** Funktion: unicode_new_u2 **********************************
445
446         Legt ein neues unicode-Symbol an. Der Text des Symbols wird dieser
447         Funktion als u2-Array "ubergeben
448
449 ******************************************************************************/
450
451 unicode *unicode_new_u2 (u2 *text, u2 length)
452 {
453         u4 key = u_hashkey (text, length);
454         u4 slot = key % unicodehashsize;
455         unicode *u = unicodehash[slot];
456         u2 i;
457
458         while (u) {
459                 if (u->key == key) {
460                         if (u->length == length) {
461                                 for (i=0; i<length; i++) {
462                                         if (text[i] != u->text[i]) goto nomatch;
463                                         }       
464                                         return u;
465                                 }
466                         }
467                 nomatch:
468                 u = u->hashlink;
469                 }
470
471 #ifdef STATISTICS
472         count_unicode_len += sizeof(unicode) + 2 * length;
473 #endif
474
475         u = NEW (unicode);
476         u->key = key;
477         u->length = length;
478         u->text = MNEW (u2, length);
479         u->class = NULL;
480         u->string = NULL;
481         u->hashlink = unicodehash[slot];
482         unicodehash[slot] = u;
483         for (i=0; i<length; i++) u->text[i] = text[i];
484
485         unicodeentries++;
486         
487         if ( unicodeentries > (unicodehashsize/2)) u_reorganizehash();
488         
489         return u;
490 }
491
492
493 /********************* Funktion: unicode_new_char *****************************
494
495         Legt ein neues unicode-Symbol an. Der Text des Symbols wird dieser
496         Funktion als C-String ( = char* ) "ubergeben
497
498 ******************************************************************************/
499
500 unicode *unicode_new_char (char *text)
501 {
502 #define MAXNEWCHAR 500
503         u2 buffer[MAXNEWCHAR];
504         u2 length = 0;
505         u1 c;
506         
507         while ( (c = *text) != '\0' ) {
508                 if (length>=MAXNEWCHAR) panic ("Text too long in unicode_new_char");
509                 buffer[length++] = c;
510                 text ++;
511                 }
512         return unicode_new_u2 (buffer, length);
513 }
514
515
516 /********************** Funktion: unicode_setclasslink ************************
517
518         H"angt einen Verweis auf eine Klasse an ein unicode-Symbol an.
519
520 ******************************************************************************/
521
522 void unicode_setclasslink (unicode *u, classinfo *class)
523 {
524         PANICIF (u->class, "Attempt to attach class to already attached symbol");
525         u->class = class;
526 }
527
528 /********************** Funktion: unicode_getclasslink ************************
529
530         Sucht den Verweis von einem unicode-Symbol auf eine Klasse.
531         Wenn keine solche Klasse existiert, dann wird ein Fehler
532         ausgegeben.
533
534 ******************************************************************************/
535
536 classinfo *unicode_getclasslink (unicode *u)
537 {
538         PANICIF (!u->class, "Attempt to get unknown class-reference");
539         return u->class;
540 }
541
542
543
544 /********************* Funktion: unicode_unlinkclass *************************
545
546         Entfernt den Verweis auf eine Klasse wieder von einem Symbol
547         
548 ******************************************************************************/
549
550 void unicode_unlinkclass (unicode *u)
551 {
552         PANICIF (!u->class, "Attempt to unlink not yet linked symbol");
553         u -> class = NULL;
554 }
555
556
557
558 /******************* Funktion> unicode_setstringlink *********************
559
560         H"angt einen Verweis auf einen konstanten String an ein 
561         Unicode-Symbol
562         
563 *************************************************************************/
564
565 void unicode_setstringlink (unicode *u, java_objectheader *str)
566 {
567         PANICIF (u->string, "Attempt to attach string to already attached symbol");
568         u->string = str;
569 }
570
571
572 /********************* Funktion: unicode_unlinkstring *************************
573
574         Entfernt den Verweis auf einen String wieder von einem Symbol
575         
576 ******************************************************************************/
577
578 void unicode_unlinkstring (unicode *u)
579 {
580         PANICIF (!u->class, "Attempt to unlink not yet linked symbol");
581         u -> string = NULL;
582 }
583
584
585
586 /*********************** Funktion: unicode_show ******************************
587
588         gibt eine Aufstellung aller Symbol im unicode-hash auf stdout aus.
589         (nur f"ur Debug-Zwecke)
590         
591 *****************************************************************************/
592
593 void unicode_show ()
594 {
595         unicode *u;
596         u4 i;
597
598         printf ("UNICODE-HASH: %d slots for %d entries\n", 
599                  (int) unicodehashsize, (int) unicodeentries );
600                   
601         for (i=0; i<unicodehashsize; i++) {
602                 u = unicodehash[i];
603                 if (u) {
604                         printf ("SLOT %d: ", (int) i);
605                         while (u) {
606                                 printf ("'");
607                                 unicode_display (u);
608                                 printf ("' ");
609                                 if (u->string) printf ("(string)  ");
610                                 u = u->hashlink;
611                                 }       
612                         printf ("\n");
613                         }
614                 
615                 }
616 }
617
618
619
620 /******************************************************************************
621 *********************** Diverse Support-Funktionen ****************************
622 ******************************************************************************/
623
624
625 /******************** Funktion: desc_to_type **********************************
626
627         Findet zu einem gegebenen Typdescriptor den entsprechenden 
628         Java-Grunddatentyp.
629         
630 ******************************************************************************/
631
632 u2 desc_to_type (unicode *descriptor)
633 {
634         if (descriptor->length < 1) panic ("Type-Descriptor is empty string");
635         
636         switch (descriptor->text[0]) {
637         case 'B': 
638         case 'C':
639         case 'I':
640         case 'S':  
641         case 'Z':  return TYPE_INT;
642         case 'D':  return TYPE_DOUBLE;
643         case 'F':  return TYPE_FLOAT;
644         case 'J':  return TYPE_LONG;
645         case 'L':
646         case '[':  return TYPE_ADDRESS;
647         }
648                         
649         sprintf (logtext, "Invalid Type-Descriptor: "); 
650         unicode_sprint (logtext+strlen(logtext), descriptor);
651         error (); 
652         return 0;
653 }
654
655
656 /********************** Funktion: desc_typesize *******************************
657
658         Berechnet die L"ange (in Byte) eines Datenelements gegebenen Typs,
659         der durch den Typdescriptor gegeben ist.
660         
661 ******************************************************************************/
662
663 u2 desc_typesize (unicode *descriptor)
664 {
665         switch (desc_to_type(descriptor)) {
666         case TYPE_INT:     return 4;
667         case TYPE_LONG:    return 8;
668         case TYPE_FLOAT:   return 4;
669         case TYPE_DOUBLE:  return 8;
670         case TYPE_ADDRESS: return sizeof(voidptr);
671         default:           return 0;
672         }
673 }
674
675
676
677
678
679 /******************************************************************************
680 ********************* Der garbage-collected Heap ******************************
681 *******************************************************************************
682
683         verwaltet einen Heap mit automatischer Speicherfreigabe.
684
685         (eine ausf"uhrliche Dokumentation findet sich in der Datei: 
686         collect.doc)
687         
688 ******************************************************************************/
689
690
691 bool collectverbose = false;  /* soll Meldung beim GC ausgegeben werden? */
692
693
694 #define BLOCKSIZE 8         /* Gr"osse eines Speicherblockes */
695 typedef u8 heapblock;       /* Datentyp mit der Gr"osse eines Speicherblocks */
696
697 #if U8_AVAILABLE && SUPPORT_LONG
698 #define bitfieldtype u8
699 #define BITFIELDBITS 64
700 #else
701 #define bitfieldtype u4
702 #define BITFIELDBITS 32
703 #endif
704
705 u4 heapsize;                /* Gr"osse des Heap in Blocks */
706 u4 topofheap;               /* Bisherige Obergrenze Heaps */
707 heapblock *heap;            /* Speicher f"ur den Heap selbst */
708
709 bitfieldtype *startbits;     /* Bitfeld f"ur Bereichsstartkennung */
710 bitfieldtype *markbits;      /* Bitfeld f"ur Markierung */
711 bitfieldtype *referencebits; /* Bitfeld f"ur Folgereferenzenkennung */
712
713 u4 heapfillgrade;           /* Menge der Daten im Heap */
714 u4 collectthreashold;       /* Schwellwert f"ur n"achstes GC */
715
716 void **bottom_of_stack;     /* Zeiger auf Untergrenze des C-Stacks */ 
717 chain *allglobalreferences; /* Liste f"ur alle globalen Zeiger */
718
719 typedef struct finalizernode {
720         struct finalizernode *next;     
721         u4 objstart;
722         methodinfo *finalizer;
723         } finalizernode;
724         
725 finalizernode *livefinalizees;
726 finalizernode *deadfinalizees;
727
728
729 typedef struct memarea {    /* Datenstruktur f"ur einen Freispeicherbereich */
730         struct memarea *next;
731         } memarea;
732
733 typedef struct bigmemarea {   /* Datenstruktur f"ur einen */
734         struct bigmemarea *next;  /* Freispeicherbereich variabler L"ange */
735         u4 size;
736         } bigmemarea;
737         
738 #define DIFFERENTSIZES 128         /* Anzahl der 'kleinen' Freispeicherlisten */
739 memarea *memlist[DIFFERENTSIZES];  /* Die 'kleinen' Freispeicherlisten */
740 bitfieldtype memlistbits[DIFFERENTSIZES/BITFIELDBITS]; 
741                                    /* Bitfeld, in dem jeweils ein Bit gesetzt */
742                                    /* ist, wenn eine Liste noch etwas enth"alt */
743
744 bigmemarea *bigmemlist;         /* Liste der gr"osseren Freispeicherbereiche */
745
746
747
748
749 /**************** Hilfsfunktion: lowest **************************************
750
751 liefert als Ergebnis die Nummer des niederwertigsten Bits einer 
752 Zahl vom Typ bitfieldtype, das 1 ist.
753 Wenn die ganze Zahl keine 1en enth"alt, dann ist egal, was f"ur einen
754 Wert die Funktion l"iefert.
755 z.B.: lowest(1) = 0,   lowest(12) = 2,   lowest(1024) = 10
756
757 *****************************************************************************/
758
759 static u1 lowesttable[256] = {
760         255, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
761         4,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
762         5,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
763         4,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
764         6,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
765         4,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
766         5,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
767         4,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
768         7,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
769         4,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
770         5,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
771         4,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
772         6,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
773         4,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
774         5,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
775         4,   0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 };
776         
777 static int lowest(bitfieldtype i)
778 {
779 #if BITFIELDBITS==64
780         u8 i1 = i<<32;
781         if (i1) {
782                 u8 i11 = i1<<16;
783                 if (i11) {
784                         u8 i111 = i11<<8;
785                         if (i111) return lowesttable[i111>>56];
786                         else      return 8+lowesttable[i11>>56];
787                         }
788                 else {
789                         u8 i112 = i1<<8;
790                         if (i112) return 16+lowesttable[i112>>56];
791                         else      return 24+lowesttable[i1>>56];
792                         }
793                 }
794         else {
795                 u8 i12 = i<<16;
796                 if (i12) {
797                         u8 i121 = i12<<8;
798                         if (i121) return 32+lowesttable[i121>>56];
799                         else      return 40+lowesttable[i12>>56];
800                         }
801                 else {
802                         u8 i122 = i<<8;
803                         if (i122) return 48+lowesttable[i122>>56];
804                         else      return 56+lowesttable[i>>56];
805                         }
806                 }
807 #else
808         u4 i1 = i<<16;
809         if (i1) {
810                 u4 i11 = i1<<8;
811                 if (i11) return lowesttable[i11>>24];
812                 else     return 8+lowesttable[i1>>24];
813                 }
814         else {
815                 u4 i12 = i<<8;
816                 if (i12) return 16+lowesttable[i12>>24];
817                 else     return 24+lowesttable[i>>24];
818                 }
819 #endif
820 }
821
822
823 /******** Funktionen zum Setzen und L"oschen von Bits in Bitfeldern ***********/
824
825 static void setbit(bitfieldtype *bitfield, u4 bitnumber)
826 {
827         bitfield[bitnumber/BITFIELDBITS] |= 
828           ((bitfieldtype) 1) << (bitnumber%BITFIELDBITS);
829 }
830
831 static void clearbit(bitfieldtype *bitfield, u4 bitnumber)
832 {
833         bitfield[bitnumber/BITFIELDBITS] &= 
834            ~((bitfieldtype) 1) << (bitnumber%BITFIELDBITS);
835 }
836
837 static bool isbitset(bitfieldtype *bitfield, u4 bitnumber)
838 {
839         return ( bitfield[bitnumber/BITFIELDBITS] & 
840            ( ((bitfieldtype) 1) << (bitnumber%BITFIELDBITS) ) ) != 0;
841 }
842
843 static bool isbitclear(bitfieldtype *bitfield, u4 bitnumber)
844 {
845         return ( bitfield[bitnumber/BITFIELDBITS] & 
846             ( ((bitfieldtype) 1) << (bitnumber%BITFIELDBITS) ) ) == 0;
847 }
848
849
850 /***************** Funktion: clearbitfield ************************************
851         
852         l"oscht ein ganzes Bitfeld
853         
854 ******************************************************************************/
855
856 static void clearbitfield(bitfieldtype *bitfield, u4 fieldsize)
857
858         u4 i,t;
859         t = ALIGN(fieldsize, BITFIELDBITS) / BITFIELDBITS;
860         for (i=0; i<t; i++) bitfield[i] = 0;
861 }
862
863 /************** Funktion: maskfieldwithfield **********************************
864         
865         Verkn"upft zwei Bitfelder bitweise mit UND, das erste Bitfeld
866         wird mit dem Ergebnis "uberschrieben 
867         
868 ******************************************************************************/
869         
870 static void maskfieldwithfield (bitfieldtype* bitfield, 
871                                 bitfieldtype *maskfield, u4 fieldsize)
872 {
873         u4 i,t;
874         t = ALIGN(fieldsize, BITFIELDBITS) / BITFIELDBITS;
875         for (i=0; i<t; i++) bitfield[i] &= maskfield[i];
876 }
877
878
879 /************** Funktion: findnextsetbit **************************************
880
881         Sucht in einem Bitfeld ab einer Stelle das n"achste gesetzte Bit
882         und liefert die Nummer dieses Bits.
883         Wenn kein Bit mehr zwischen 'bitnumber' und 'fieldsize' gesetzt
884         ist, dann wird fieldsize zur"uckgeliefte.
885
886 ******************************************************************************/
887
888 static u4 findnextsetbit(bitfieldtype* bitfield, u4 fieldsize, u4 bitnumber)
889 {
890         bitfieldtype pattern;
891
892         for (;;) {
893                 if (bitnumber >= fieldsize) return fieldsize;
894                 
895                 pattern = bitfield[bitnumber/BITFIELDBITS];
896                 pattern >>= (bitnumber%BITFIELDBITS);
897                 if (pattern) return bitnumber + lowest(pattern);
898
899                 bitnumber = ((bitnumber + BITFIELDBITS) / BITFIELDBITS) * BITFIELDBITS;
900                 }
901 }
902
903
904 /************ Funktion: findnextcombination_set_unset *************************
905
906         funktioniert wie findnextsetbit, allerdings sucht diese Funktion
907         nach einer Stelle, an der gleichzeitig ein Bit im ersten
908         Bitfeld gesetzt ist und im zweiten Bitfeld das entsprechende
909         Bit nicht gesetzt ist.
910
911 ******************************************************************************/
912
913 static u4 findnextcombination_set_unset 
914         (bitfieldtype *bitfield1, bitfieldtype* bitfield2, u4 fieldsize, u4 bitnumber)
915 {
916         bitfieldtype pattern;
917
918         for (;;) {
919                 if (bitnumber >= fieldsize) return fieldsize;
920                 
921                 pattern =     bitfield1[bitnumber/BITFIELDBITS] 
922                           & (~bitfield2[bitnumber/BITFIELDBITS]);
923                 pattern >>= (bitnumber%BITFIELDBITS);
924                 if (pattern) return bitnumber + lowest(pattern);
925
926                 bitnumber = ((bitnumber + BITFIELDBITS) / BITFIELDBITS) * BITFIELDBITS;
927                 }
928 }
929
930
931
932 /************** Funktion: memlist_init ****************************************
933
934         initialisiert die Freispeicherlisten (zum nachfolgenden Eintragen 
935         mit memlist_addrange).
936
937 ******************************************************************************/
938
939 static void memlist_init ()
940 {
941         u4 i;
942         for (i=0; i<DIFFERENTSIZES; i++) memlist[i] = NULL;
943         clearbitfield (memlistbits, DIFFERENTSIZES);
944         bigmemlist = NULL;
945 }
946
947
948 /************** Funktion: memlist_addrange ************************************
949
950         f"ugt einen Bereich von Heap-Bl"ocken zur Freispeicherliste 
951         hinzu (in die freien Heap-Bl"ocke werden dabei verschiedene 
952         Verkettungszeiger hineingeschrieben).
953
954 ******************************************************************************/
955
956 static void memlist_addrange (u4 freestart, u4 freesize)
957 {
958         if (freesize>=DIFFERENTSIZES) {
959                 bigmemarea *m = (bigmemarea*) (heap+freestart);
960                 m -> next = bigmemlist;
961                 m -> size = freesize;
962                 bigmemlist = m;
963                 }
964         else {
965                 if (freesize*BLOCKSIZE>=sizeof(memarea)) {
966                         memarea *m = (memarea*) (heap+freestart);
967                         m -> next = memlist[freesize];
968                         memlist[freesize] = m;
969                         setbit (memlistbits, freesize);
970                         }
971                 }
972 }
973
974
975 /************** Funktion: memlist_getsuitable *********************************
976
977         sucht in der Freispeicherliste einen Speicherbereich, der m"oglichst
978         genau die gew"unschte L"ange hat.
979         Der Bereich wird dabei auf jeden Fall aus der Liste ausgetragen.
980         (Wenn der Bereich zu lang sein sollte, dann kann der Aufrufer den
981         Rest wieder mit 'memlist_addrange' in die Liste einh"angen)
982         
983         Return (in Referenzparametern): 
984                 *freestart: Anfang des freien Speichers
985                 *freelength: L"ange dieses Speicherbereiches
986
987         Wenn kein passender Speicherblock mehr gefunden werden kann, dann 
988         wird in '*freelength' 0 hineingeschrieben.
989         
990 ******************************************************************************/         
991
992 static void memlist_getsuitable (u4 *freestart, u4 *freelength, u4 length)
993 {
994         bigmemarea *m;
995         bigmemarea *prevm = NULL;
996         
997         if (length<DIFFERENTSIZES) {
998                 u4 firstfreelength;
999
1000                 if (memlist[length]) {
1001                         firstfreelength = length;
1002                         }
1003                 else {
1004                         firstfreelength = findnextsetbit 
1005                                 (memlistbits, DIFFERENTSIZES, length+3); 
1006                                 /* wenn kein passender Block da ist, dann gleich nach */
1007                                 /* einem etwas gr"osseren suchen, damit keine kleinen */
1008                                 /* St"uckchen "ubrigbleiben */
1009                         }
1010                         
1011                 if (firstfreelength<DIFFERENTSIZES) {
1012                         memarea *m = memlist[firstfreelength];
1013                         memlist[firstfreelength] = m->next;             
1014                         if (!m->next) clearbit (memlistbits, firstfreelength);
1015                         *freestart = ((heapblock*) m) - heap;
1016                         *freelength = firstfreelength;
1017                         return;
1018                         }
1019                 }
1020
1021         m = bigmemlist;
1022         while (m) {
1023                 if (m->size >= length) {
1024                         if (prevm) prevm->next = m->next;                                       
1025                                 else   bigmemlist = m->next;
1026                         
1027                         *freestart = ((heapblock*) m) - heap;
1028                         *freelength = m->size;
1029                         return ;                        
1030                         }
1031
1032                 prevm = m;
1033                 m = m->next;
1034                 }
1035         
1036         *freelength=0;
1037 }
1038
1039
1040
1041
1042
1043 /******************* Funktion: mark *******************************************
1044
1045         Markiert ein m"oglicherweise g"ultiges Objekt.
1046         Sollte sich herausstellen, dass der Zeiger gar nicht auf ein Objekt
1047         am Heap zeigt, dann wird eben gar nichts markiert.
1048
1049 ******************************************************************************/
1050
1051 static void markreferences (void **rstart, void **rend);
1052
1053 static void mark (heapblock *obj)
1054 {
1055         u4 blocknum,objectend;
1056
1057         if ((long) obj & (BLOCKSIZE-1)) return;
1058         
1059         if (obj<heap) return;
1060         if (obj>=(heap+topofheap) ) return;
1061
1062         blocknum = obj-heap;
1063         if ( isbitclear(startbits, blocknum) ) return;
1064         if ( isbitset(markbits, blocknum) ) return;
1065
1066         setbit (markbits, blocknum);
1067         
1068         if ( isbitclear(referencebits, blocknum) ) return;
1069
1070         objectend = findnextsetbit (startbits, topofheap, blocknum+1);
1071         markreferences ((void**)obj, (void**) (heap+objectend) );
1072 }
1073
1074
1075 /******************** Funktion: markreferences ********************************
1076
1077         Geht einen Speicherbereich durch, und markiert alle Objekte, auf
1078         die von diesem Bereich aus irgendeine Referenz existiert.
1079
1080 ******************************************************************************/
1081
1082 static void markreferences (void **rstart, void **rend)
1083 {
1084         void **ptr;
1085         
1086         for (ptr=rstart; ptr<rend; ptr++) mark (*ptr);
1087 }
1088
1089
1090 /******************* Funktion: markstack **************************************
1091
1092         Marks all objects that are referenced by the (C-)stacks of
1093         all live threads.
1094
1095         (The stack-bottom is to be specified in the call to heap_init).
1096
1097 ******************************************************************************/
1098
1099 static void markstack ()                   /* schani */
1100 {
1101         void *dummy;
1102
1103 #ifdef USE_THREADS
1104     thread *aThread;
1105
1106         if (currentThread == NULL) {
1107                 void **top_of_stack = &dummy;
1108                                 
1109                 if (top_of_stack > bottom_of_stack)
1110                         markreferences(bottom_of_stack, top_of_stack);
1111                 else
1112                         markreferences(top_of_stack, bottom_of_stack);
1113         }
1114         else {
1115                 for (aThread = liveThreads; aThread != 0;
1116                          aThread = CONTEXT(aThread).nextlive) {
1117                         mark((heapblock*)aThread);
1118                         if (aThread == currentThread) {
1119                                 void **top_of_stack = &dummy;
1120                                 
1121                                 if (top_of_stack > (void**)CONTEXT(aThread).stackEnd)
1122                                         markreferences((void**)CONTEXT(aThread).stackEnd, top_of_stack);
1123                                 else    
1124                                         markreferences(top_of_stack, (void**)CONTEXT(aThread).stackEnd);
1125                         }
1126                         else {
1127                                 if (CONTEXT(aThread).usedStackTop > CONTEXT(aThread).stackEnd)
1128                                         markreferences((void**)CONTEXT(aThread).stackEnd,
1129                                                                    (void**)CONTEXT(aThread).usedStackTop);
1130                                 else    
1131                                         markreferences((void**)CONTEXT(aThread).usedStackTop,
1132                                                                    (void**)CONTEXT(aThread).stackEnd);
1133                         }
1134             }
1135
1136                 markreferences((void**)&threadQhead[0],
1137                                            (void**)&threadQhead[MAX_THREAD_PRIO]);
1138         }
1139 #else
1140     void **top_of_stack = &dummy;
1141
1142     if (top_of_stack > bottom_of_stack)
1143         markreferences(bottom_of_stack, top_of_stack);
1144     else
1145         markreferences(top_of_stack, bottom_of_stack);
1146 #endif
1147 }
1148
1149
1150
1151 /**************** Funktion: searchlivefinalizees *****************************
1152
1153         geht die Liste aller Objekte durch, die noch finalisiert werden m"ussen
1154         (livefinalizees), und tr"agt alle nicht mehr markierten in die
1155         Liste deadfinalizess ein (allerdings werden sie vorher noch als
1156         erreicht markiert, damit sie nicht jetzt gleich gel"oscht werden).
1157         
1158 *****************************************************************************/ 
1159
1160 static void searchlivefinalizees ()
1161 {
1162         finalizernode *fn = livefinalizees;
1163         finalizernode *lastlive = NULL;
1164                 
1165         while (fn) {
1166         
1167                 /* alle zu finalisierenden Objekte, die nicht mehr markiert sind: */
1168                 if (isbitclear (markbits, fn->objstart)) {
1169                         finalizernode *nextfn = fn->next;
1170
1171                         mark (heap + fn->objstart); 
1172
1173                         if (lastlive) lastlive -> next = nextfn;
1174                                        else livefinalizees = nextfn;
1175
1176                         fn -> next = deadfinalizees;
1177                         deadfinalizees = fn;
1178                         
1179                         fn = nextfn;
1180                         }
1181                 else {  
1182                         lastlive = fn;
1183                         fn = fn->next;
1184                         }
1185                 }
1186 }
1187
1188
1189
1190 /********************** Funktion: finalizedead *******************************
1191
1192         ruft die 'finalize'-Methode aller Objekte in der 'deadfinalizees'-
1193         Liste auf.
1194         Achtung: Es kann hier eventuell zu neuerlichen Speicheranforderungen
1195         (mit potentiell notwendigem GC) kommen, deshalb m"ussen manche
1196         globalen Variablen in lokale Variblen kopiert werden 
1197         (Reentrant-F"ahigkeit!!!)
1198          
1199 ******************************************************************************/
1200
1201 static void finalizedead()
1202 {
1203         finalizernode *fn = deadfinalizees;
1204         deadfinalizees = NULL;
1205         
1206         while (fn) {
1207                 finalizernode *nextfn = fn->next;
1208                 
1209                 asm_calljavamethod (fn->finalizer, heap+fn->objstart, NULL,NULL,NULL);
1210                 FREE (fn, finalizernode);
1211                 
1212                 fn = nextfn;
1213                 }
1214
1215 }
1216
1217
1218
1219 /****************** Funktion: heap_docollect **********************************
1220         
1221         F"uhrt eine vollst"andige Garbage Collection durch
1222         
1223 ******************************************************************************/
1224
1225 static void heap_docollect ()
1226 {
1227         u4 freestart,freeend;
1228         void **p;
1229         bitfieldtype *dummy;
1230         u4 heapfreemem;
1231         u4 oldfillgrade;
1232
1233
1234         if (runverbose) {
1235                 fprintf(stderr, "doing garbage collection\n");
1236                 }
1237                 /* alle Markierungsbits l"oschen */
1238         clearbitfield (markbits, topofheap);
1239
1240                 /* Alle vom Stack referenzierten Objekte markieren */
1241         asm_dumpregistersandcall (markstack);
1242
1243                 /* Alle von globalen Variablen erreichbaren Objekte markieren */
1244         p = chain_first (allglobalreferences);
1245         while (p) {
1246                 mark (*p);
1247                 p = chain_next (allglobalreferences);   
1248                 }
1249
1250                 /* alle Objekte durchsehen, die eine finalizer-Methode haben */
1251         searchlivefinalizees();
1252
1253                 /* alle Reference-Bits l"oschen, deren Objekte nicht */
1254                 /* mehr erreichbar sind */
1255         maskfieldwithfield (referencebits, markbits, topofheap);
1256
1257
1258                 /* Freispeicherliste initialisieren */
1259         memlist_init ();
1260         
1261         
1262                 /* Heap schrittweise durchgehen, und alle freien Bl"ocke merken */
1263
1264         heapfreemem = 0;
1265         freeend=0;
1266         for (;;) {
1267                         /* Anfang des n"achsten freien Bereiches suchen */
1268                 freestart = findnextcombination_set_unset 
1269                         (startbits, markbits, topofheap, freeend);
1270
1271                         /* Wenn es keinen freien Bereich mehr gibt -> fertig */
1272                 if (freestart>=topofheap) goto freememfinished;
1273
1274                         /* Anfang des freien Bereiches markieren */
1275                 setbit (markbits, freestart);
1276
1277                         /* Ende des freien Bereiches suchen */          
1278                 freeend = findnextsetbit (markbits, topofheap, freestart+1);
1279
1280                         /* Freien Bereich in Freispeicherliste einh"angen */
1281                 memlist_addrange (freestart, freeend-freestart);
1282
1283                         /* Menge des freien Speichers mitnotieren */
1284                 heapfreemem += (freeend-freestart);
1285                 }
1286
1287         freememfinished:
1288
1289                 /* Die Rollen von markbits und startbits vertauschen */ 
1290         dummy = markbits;
1291         markbits = startbits;
1292         startbits = dummy;
1293
1294
1295                 /* Threashold-Wert f"ur n"achstes Collect */
1296         oldfillgrade = heapfillgrade;
1297         heapfillgrade = topofheap - heapfreemem;
1298         collectthreashold = heapfillgrade*3;   /* eine nette Heuristik */
1299
1300                 /* Eventuell eine Meldung ausgeben */
1301         if (collectverbose) {
1302                 sprintf (logtext, "Garbage Collection:  previous/now = %d / %d ",
1303                   (int) (oldfillgrade * BLOCKSIZE), 
1304                   (int) (heapfillgrade * BLOCKSIZE) );
1305                 dolog ();
1306                 }
1307
1308
1309                 
1310                 /* alle gerade unerreichbar gewordenen Objekte mit 
1311                    finalize-Methoden jetzt finalisieren.
1312                    Achtung: Diese Funktion kann zu neuerlichem GC f"uhren!! */
1313         finalizedead ();
1314         
1315 }
1316
1317 /************************* Function: gc_init **********************************
1318
1319   Initializes anything that must be initialized to call the gc on the right
1320   stack.
1321
1322 ******************************************************************************/
1323
1324 void
1325 gc_init (void)
1326 {
1327 }
1328
1329 /************************** Function: gc_call ********************************
1330
1331   Calls the garbage collector. The garbage collector should always be called
1332   using this function since it ensures that enough stack space is available.
1333
1334 ******************************************************************************/
1335
1336 void
1337 gc_call (void)
1338 {
1339 #ifdef USE_THREADS
1340         assert(blockInts == 0);
1341 #endif
1342
1343         intsDisable();
1344         if (currentThread == NULL || currentThread == mainThread)
1345                 heap_docollect();
1346         else
1347                 asm_switchstackandcall(CONTEXT(mainThread).usedStackTop, heap_docollect);
1348         intsRestore();
1349 }
1350
1351
1352 /************************* Funktion: heap_init ********************************
1353
1354         Initialisiert den Garbage Collector.
1355         Parameter: 
1356                 heapbytesize:      Maximale Gr"osse des Heap (in Bytes)
1357                 heapbytestartsize: Gr"osse des Heaps, bei dem zum ersten mal eine
1358                                    GC durchgef"uhrt werden soll.
1359                 stackbottom:       Ein Zeiger auf die Untergrenze des Stacks, im dem
1360                                Referenzen auf Objekte stehen k"onnen.                  
1361                                            
1362 ******************************************************************************/
1363
1364 void heap_init (u4 heapbytesize, u4 heapbytestartsize, void **stackbottom)
1365 {
1366
1367 #ifdef TRACECALLARGS
1368
1369         heapsize = ALIGN (heapbytesize, getpagesize());
1370         heapsize = heapsize/BLOCKSIZE;
1371         heap = (void*) mmap ((void*) 0x10000000, (size_t) (heapsize * BLOCKSIZE),
1372                PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, (off_t) 0);
1373         if (heap != (void *) 0x10000000) {
1374                 perror("mmap");
1375                 printf("address = %p\n", heap);
1376                 panic("mmap failed\n");
1377                 }
1378
1379 #else
1380
1381         heapsize = ALIGN (heapbytesize, 1024);
1382         heapsize = heapsize/BLOCKSIZE;
1383         heap = MNEW (heapblock, heapsize);
1384
1385 #endif
1386
1387         topofheap = 0;
1388         startbits = MNEW (bitfieldtype, heapsize/BITFIELDBITS);
1389         markbits = MNEW (bitfieldtype, heapsize/BITFIELDBITS);
1390         referencebits = MNEW (bitfieldtype, heapsize/BITFIELDBITS);
1391         clearbitfield (startbits, heapsize);
1392         clearbitfield (markbits, heapsize);
1393         clearbitfield (referencebits, heapsize);
1394
1395         heapfillgrade = 0;
1396         collectthreashold = heapbytestartsize/BLOCKSIZE;
1397         allglobalreferences = chain_new ();
1398         bottom_of_stack = stackbottom;
1399
1400         livefinalizees = NULL;
1401         deadfinalizees = NULL;
1402 }
1403
1404
1405 /****************** Funktion: heap_close **************************************
1406
1407         Gibt allen ben"otigten Speicher frei
1408
1409 ******************************************************************************/
1410
1411 void heap_close ()
1412 {
1413 #ifndef TRACECALLARGS
1414         MFREE (heap, heapblock, heapsize); */
1415 #endif
1416         MFREE (startbits, bitfieldtype, heapsize/BITFIELDBITS);
1417         MFREE (markbits, bitfieldtype, heapsize/BITFIELDBITS);
1418         MFREE (referencebits, bitfieldtype, heapsize/BITFIELDBITS);
1419         chain_free (allglobalreferences);
1420
1421         while (livefinalizees) {
1422                 finalizernode *n = livefinalizees->next;
1423                 FREE (livefinalizees, finalizernode);
1424                 livefinalizees = n;
1425                 }
1426 }
1427
1428
1429 /***************** Funktion: heap_addreference ********************************
1430
1431         Teilt dem GC eine Speicherstelle mit, an der eine globale Referenz
1432         auf Objekte gespeichert sein kann.
1433
1434 ******************************************************************************/
1435
1436 void heap_addreference (void **reflocation)
1437 {
1438         intsDisable();                     /* schani */
1439
1440         chain_addlast (allglobalreferences, reflocation);
1441
1442         intsRestore();                    /* schani */
1443 }
1444
1445
1446
1447 /***************** Funktion: heap_allocate ************************************
1448
1449         Fordert einen Speicher vom Heap an, der eine gew"unschte Gr"osse
1450         (in Byte angegeben) haben muss.
1451         Wenn kein Speicher mehr vorhanden ist (auch nicht nach einem
1452         Garbage Collection-Durchlauf), dann wird NULL zur"uckgegeben.
1453         Zus"atzlich wird durch den Parameter 'references' angegeben, ob
1454         in das angelegte Objekt Referenzen auf andere Objekte eingetragen
1455         werden k"onnten. 
1456         (Wichtig wegen Beschleunigung des Mark&Sweep-Durchlauf)
1457         Im Zweifelsfalle immer references=true verwenden.
1458
1459 ******************************************************************************/
1460
1461 void *heap_allocate (u4 bytelength, bool references, methodinfo *finalizer)
1462 {
1463         u4 freestart,freelength;
1464         u4 length = ALIGN(bytelength, BLOCKSIZE) / BLOCKSIZE;
1465         
1466         intsDisable();                        /* schani */
1467
1468         memlist_getsuitable (&freestart, &freelength, length);
1469
1470 onemoretry:
1471         if (!freelength) {
1472                 if (    (topofheap+length > collectthreashold) 
1473                      || (topofheap+length > heapsize) ) {
1474
1475                         intsRestore();
1476                         gc_call();
1477                         intsDisable();
1478                         
1479                         memlist_getsuitable (&freestart, &freelength, length);
1480                         if (freelength) goto onemoretry;
1481                         }
1482                 
1483                 if (topofheap+length > heapsize) {
1484                         sprintf (logtext, "Heap-Allocation failed for %d bytes", 
1485                             (int) bytelength);
1486                         dolog();
1487                         intsRestore();            /* schani */
1488                         return NULL;
1489                         }
1490                         
1491                 freestart = topofheap;
1492                 freelength = length;
1493                 setbit (startbits, topofheap);
1494                 topofheap += length;
1495                 }
1496         else {
1497                 if (freelength>length) {
1498                         setbit (startbits, freestart+length);
1499                         memlist_addrange (freestart+length, freelength-length);
1500                         }
1501                 }
1502                 
1503         if (references) setbit (referencebits, freestart);
1504
1505         heapfillgrade += length;
1506
1507         if (finalizer) {
1508                 finalizernode *n = NEW(finalizernode);
1509                 n -> next = livefinalizees;
1510                 n -> objstart = freestart;
1511                 n -> finalizer = finalizer;
1512                 livefinalizees = n;
1513                 }
1514         
1515         intsRestore();                   /* schani */
1516
1517         if (runverbose) {
1518                 sprintf (logtext, "new returns: %lx", (long) (heap + freestart));
1519                 dolog ();
1520                 }
1521
1522         return (void*) (heap + freestart);
1523 }
1524
1525
1526
1527