@@ -19,9 +19,11 @@ struct Space {
1919#define INSPACE (p , sp ) ((sp)->bot <= (char *) (p) && (char *) (p) < (sp)->top)
2020
2121#define MIN_minspace 10000
22+ #define MIN_minpspace 1000
2223
2324#if GCPROTECT
24- #define NSPACES 10
25+ #define NSPACES 12
26+ #define FIRSTSPACE 1
2527#endif
2628
2729#if HAVE_SYSCONF
@@ -38,12 +40,13 @@ int gcblocked = 0;
3840Tag StringTag ;
3941
4042/* own variables */
41- static Space * new , * old ;
43+ static Space * new , * old , * pspace ;
4244#if GCPROTECT
4345static Space * spaces ;
4446#endif
4547static Root * globalrootlist , * exceptionrootlist ;
4648static size_t minspace = MIN_minspace ; /* minimum number of bytes in a new space */
49+ static size_t minpspace = MIN_minpspace ;
4750
4851
4952/*
@@ -136,14 +139,15 @@ static void initmmu(void) {
136139#if GCPROTECT
137140
138141/* mkspace -- create a new ``half'' space in debugging mode */
139- static Space * mkspace (Space * space , Space * next ) {
142+ static Space * mkspace (Space * space , Space * next , size_t size ) {
140143 assert (space == NULL || (& spaces [0 ] <= space && space < & spaces [NSPACES ]));
141144
145+ /* find and clear out any existing/next spaces */
142146 if (space != NULL ) {
143147 Space * sp ;
144148 if (space -> bot == NULL )
145149 sp = NULL ;
146- else if ((size_t ) SPACESIZE (space ) < minspace )
150+ else if ((size_t ) SPACESIZE (space ) < size )
147151 sp = space ;
148152 else {
149153 sp = space -> next ;
@@ -160,12 +164,13 @@ static Space *mkspace(Space *space, Space *next) {
160164 }
161165 }
162166
167+ /* build new space (or set up existing &space[n]) */
163168 if (space == NULL ) {
164169 space = ealloc (sizeof (Space ));
165170 memzero (space , sizeof (Space ));
166171 }
167172 if (space -> bot == NULL ) {
168- size_t n = PAGEROUND (minspace );
173+ size_t n = PAGEROUND (size );
169174 space -> bot = take (n );
170175 space -> top = space -> bot + n / (sizeof (* space -> bot ));
171176 }
@@ -175,20 +180,23 @@ static Space *mkspace(Space *space, Space *next) {
175180
176181 return space ;
177182}
178- #define newspace (next ) mkspace(NULL, next)
183+ #define newspace (next ) mkspace(NULL, next, minspace)
184+ #define newpspace (next ) mkspace(NULL, next, minpspace)
179185
180186#else /* !GCPROTECT */
181187
182188/* newspace -- create a new ``half'' space */
183- static Space * newspace (Space * next ) {
184- size_t n = ALIGN (minspace );
189+ static Space * newspacesz (Space * next , size_t size ) {
190+ size_t n = ALIGN (size );
185191 Space * space = ealloc (sizeof (Space ) + n );
186192 space -> bot = (void * ) & space [1 ];
187193 space -> top = (void * ) (((char * ) space -> bot ) + n );
188194 space -> current = space -> bot ;
189195 space -> next = next ;
190196 return space ;
191197}
198+ #define newspace (next ) newspacesz(next, minspace)
199+ #define newpspace (next ) newspacesz(next, minpspace)
192200
193201#endif /* !GCPROTECT */
194202
@@ -273,12 +281,20 @@ extern void exceptionunroot(void) {
273281#define FOLLOWTO (p ) ((Tag *) (((char *) p) + 1))
274282#define FOLLOW (tagp ) ((void *) (((char *) tagp) - 1))
275283
284+ /* TODO: remove pmode: it's the Wrong Thing */
285+ static Boolean pmode = FALSE;
286+
276287/* forward -- forward an individual pointer from old space */
277288extern void * forward (void * p ) {
278289 Tag * tag ;
279290 void * np ;
280291
281- if (!isinspace (old , p )) {
292+ if (pmode && !isinspace (pspace , p )) {
293+ VERBOSE (("GC %8ux : <<not in pspace>>\n" , p ));
294+ return p ;
295+ }
296+
297+ if (!pmode && !isinspace (old , p )) {
282298 VERBOSE (("GC %8ux : <<not in old space>>\n" , p ));
283299 return p ;
284300 }
@@ -297,6 +313,12 @@ extern void *forward(void *p) {
297313 VERBOSE (("%s -> %8ux (forwarded)\n" , tag -> typename , np ));
298314 TAG (p ) = FOLLOWTO (np );
299315 }
316+
317+ if (pmode ) {
318+ tag = TAG (np );
319+ (* tag -> scan )(np );
320+ }
321+
300322 return np ;
301323}
302324
@@ -395,8 +417,8 @@ extern void gc(void) {
395417 for (; new -> next != NULL ; new = new -> next )
396418 ;
397419 if (++ new >= & spaces [NSPACES ])
398- new = & spaces [0 ];
399- new = mkspace (new , NULL );
420+ new = & spaces [FIRSTSPACE ];
421+ new = mkspace (new , NULL , minspace );
400422#else
401423 new = newspace (NULL );
402424#endif
@@ -425,7 +447,7 @@ extern void gc(void) {
425447#if GCINFO
426448 if (gcinfo )
427449 eprint (
428- "[GC: old %8d live %8d min %8d (pid %5d)]\n" ,
450+ "[ GC: old %8d live %8d min %8d (pid %5d)]\n" ,
429451 olddata , livedata , minspace , getpid ()
430452 );
431453#endif
@@ -439,15 +461,91 @@ extern void gc(void) {
439461 } while (new -> next != NULL );
440462}
441463
464+ /* pseal -- collect pspace to new with p as its only root, and return the collected p */
465+ extern void * pseal (void * p ) {
466+ size_t psize = 0 ;
467+ Space * sp ;
468+ #if GCINFO
469+ size_t newdata = 0 , livedata = 0 ;
470+ #endif
471+ #if GCPROTECT
472+ Space * base ;
473+ #endif
474+
475+ for (sp = pspace ; sp != NULL ; sp = sp -> next )
476+ psize += SPACEUSED (sp );
477+
478+ if (psize == 0 )
479+ return p ;
480+
481+ /* TODO: this is an overestimate since it counts garbage */
482+ gcreserve (psize );
483+ VERBOSE (("Reserved %d for pspace copy\n" , psize ));
484+
485+ #if GCINFO
486+ if (gcinfo )
487+ for (sp = new ; sp != NULL ; sp = sp -> next )
488+ newdata += SPACEUSED (sp );
489+ #endif
490+
491+ assert (gcblocked >= 0 );
492+ ++ gcblocked ;
493+
494+ #if GCVERBOSE
495+ for (sp = pspace ; sp != NULL ; sp = sp -> next )
496+ VERBOSE (("GC pspace = %ux ... %ux\n" , sp -> bot , sp -> current ));
497+ #endif
498+ if (p != NULL ) {
499+ VERBOSE (("GC new space = %ux ... %ux\n" , new -> bot , new -> top ));
500+
501+ pmode = TRUE;
502+ p = forward (p );
503+ (* (TAG (p ))-> scan )(p );
504+ pmode = FALSE;
505+ }
506+
507+ #if GCINFO
508+ if (gcinfo ) {
509+ for (sp = new ; sp != NULL ; sp = sp -> next )
510+ livedata += SPACEUSED (sp );
511+ eprint (
512+ "[pseal: old %8d live %8d min %8d diff %5d (pid %5d)]\n" ,
513+ psize , livedata , minpspace , (livedata - newdata ), getpid ()
514+ );
515+ }
516+ #endif
517+
518+ if (psize > minpspace )
519+ minpspace = psize * 2 ;
520+ else if (psize < minpspace / 2 && MIN_minpspace <= minpspace / 2 )
521+ minpspace /= 2 ;
522+
523+ #if GCPROTECT
524+ for (base = pspace ; base -> next != NULL ; base = base -> next )
525+ ;
526+ #endif
527+ deprecate (pspace );
528+ #if GCPROTECT
529+ pspace = mkspace (base , NULL , minpspace );
530+ #else
531+ pspace = newpspace (NULL );
532+ #endif
533+
534+ -- gcblocked ;
535+ return p ;
536+ }
537+
442538/* initgc -- initialize the garbage collector */
443539extern void initgc (void ) {
444540#if GCPROTECT
445541 initmmu ();
446542 spaces = ealloc (NSPACES * sizeof (Space ));
447543 memzero (spaces , NSPACES * sizeof (Space ));
448- new = mkspace (& spaces [0 ], NULL );
544+ new = mkspace (& spaces [FIRSTSPACE ], NULL , minspace );
545+ pspace = mkspace (& spaces [0 ], NULL , minpspace );
449546#else
450547 new = newspace (NULL );
548+ pspace = newpspace (NULL );
451549#endif
452550 old = NULL ;
453551}
@@ -481,6 +579,24 @@ extern void *gcalloc(size_t nbytes, Tag *tag) {
481579 }
482580}
483581
582+ /* palloc -- allocate an object in pspace */
583+ extern void * palloc (size_t nbytes , Tag * tag ) {
584+ size_t n = ALIGN (nbytes + sizeof (Tag * ));
585+ assert (tag == NULL || tag -> magic == TAGMAGIC );
586+ for (;;) {
587+ Tag * * p = (void * ) pspace -> current ;
588+ char * q = ((char * ) p ) + n ;
589+ if (q <= pspace -> top ) {
590+ pspace -> current = q ;
591+ * p ++ = tag ;
592+ return p ;
593+ }
594+ if (minpspace < nbytes )
595+ minpspace = nbytes + sizeof (Tag * );
596+ pspace = newpspace (pspace );
597+ }
598+ }
599+
484600
485601/*
486602 * strings
@@ -503,10 +619,25 @@ extern char *gcndup(const char *s, size_t n) {
503619 RefReturn (result );
504620}
505621
622+ extern char * pndup (const char * s , size_t n ) {
623+ char * ns ;
624+
625+ ns = palloc ((n + 1 ) * sizeof (char ), & StringTag );
626+ memcpy (ns , s , n );
627+ ns [n ] = '\0' ;
628+ assert (strlen (ns ) == n );
629+
630+ return ns ;
631+ }
632+
506633extern char * gcdup (const char * s ) {
507634 return gcndup (s , strlen (s ));
508635}
509636
637+ extern char * pdup (const char * s ) {
638+ return pndup (s , strlen (s ));
639+ }
640+
510641static void * StringCopy (void * op ) {
511642 size_t n = strlen (op ) + 1 ;
512643 char * np = gcalloc (n , & StringTag );
@@ -547,12 +678,24 @@ extern char *sealbuffer(Buffer *buf) {
547678 return s ;
548679}
549680
681+ extern char * psealbuffer (Buffer * buf ) {
682+ char * s = pdup (buf -> str );
683+ efree (buf );
684+ return s ;
685+ }
686+
550687extern char * sealcountedbuffer (Buffer * buf ) {
551688 char * s = gcndup (buf -> str , buf -> current );
552689 efree (buf );
553690 return s ;
554691}
555692
693+ extern char * psealcountedbuffer (Buffer * buf ) {
694+ char * s = pndup (buf -> str , buf -> current );
695+ efree (buf );
696+ return s ;
697+ }
698+
556699extern Buffer * bufncat (Buffer * buf , const char * s , size_t len ) {
557700 while (buf -> current + len >= buf -> len )
558701 buf = expandbuffer (buf , buf -> current + len - buf -> len );
0 commit comments