12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844 |
- /*
- * Part of Scheme 48 1.9. See file COPYING for notices and license.
- *
- * Authors: David Frese, Marcus Crestani, Artem Mironov, Robert Ransom,
- * Mike Sperber, Martin Gasbichler
- */
- #include "generation_gc.h"
- #include <stdlib.h>
- #include <string.h> /* memcpy */
- #include "scheme48heap.h"
- #include "areas.h"
- #include "data.h"
- #include "memory.h"
- #include "page_alloc.h"
- #include "utils.h"
- #include "memory_map.h"
- #include "page_constants.h"
- #include "area_roots.h"
- #include <assert.h>
- #include "gc_config.h"
- #include "measure.h"
- #include "remset.h"
- #include <event.h> // s48_run_time
- #define FOR_ALL_AREAS(areas, command) \
- do { \
- Area* area = areas; \
- while (area != NULL) { \
- Area* next = area->next; \
- command; \
- area = next; \
- } \
- } while(0)
- typedef struct Generation {
- int index;
- Space* current_space;
- Space* other_space;
- /* size of the generation after its last collection */
- unsigned long last_size;
-
- /* Number of collections from this generation*/
- unsigned long self_count;
- /* Number of all collections (age_count) */
- unsigned long age_count;
- } Generation;
- static Space* make_space(int generation_index) {
- Space* space = (Space*)calloc(1, sizeof(Space));
- if (space == NULL) {
- s48_gc_error("make_space: out of memory");
- }
-
- space->generation_index = generation_index;
- return space;
- }
- typedef struct {
- /* a list of areas */
- Area* large;
-
- /* always one of the ones below or one of the small
- areas in the first generation in some cases */
- Area* small;
-
- Area* small_below;
- Area* small_above;
- /* only one area */
- Area* weaks;
- } CreationSpace;
- static CreationSpace creation_space;
- static unsigned long current_water_mark; /* pages */
- /* from young to old */
- static Generation generations[S48_GENERATIONS_COUNT];
- static char heap_is_initialized = 0;
- static char gc_forbid_count = 0;
- static unsigned long gc_count = 0;
- static long gc_seconds = 0;
- static long gc_mseconds = 0;
- static void recreate_creation_space() {
- unsigned long s_below;
- unsigned long s_above;
- /* free current areas */
- if (creation_space.small_below != NULL)
- s48_free_area(creation_space.small_below);
- if (creation_space.small_above != NULL)
- s48_free_area(creation_space.small_above);
- if (creation_space.large != NULL)
- s48_free_areas(creation_space.large);
- creation_space.large = NULL;
- if (creation_space.weaks != NULL)
- s48_free_area(creation_space.weaks);
- /* create some new ones */
- s_below = current_water_mark;
- if (s_below != 0)
- creation_space.small_below = s48_allocate_area(s_below, s_below, 0, AREA_TYPE_SIZE_SMALL);
- else
- creation_space.small_below = NULL;
- s_above = S48_CREATION_SPACE_SIZE - current_water_mark;
- if (s_above != 0)
- creation_space.small_above = s48_allocate_area(s_above, s_above, 0, AREA_TYPE_SIZE_SMALL);
- else
- creation_space.small_above = NULL;
- if (creation_space.small_below == NULL) {
- creation_space.small = creation_space.small_above;
- }
- else {
- creation_space.small = creation_space.small_below;
- }
- creation_space.weaks = s48_allocate_area(S48_MINIMUM_WEAK_AREA_SIZE,
- S48_MAXIMUM_WEAK_AREA_SIZE,
- 0,
- AREA_TYPE_SIZE_WEAKS);
- }
- /* FPage 1 */
- void s48_initialize_bibop_heap() {
- int i;
- if (heap_is_initialized == 1) return;
- s48_initialize_page_allocation();
- current_water_mark = S48_DEFAULT_WATER_MARK;
-
- creation_space.small_below = NULL;
- creation_space.small_above = NULL;
- creation_space.large = NULL;
- creation_space.weaks = NULL;
- recreate_creation_space();
- for (i = 0; i < S48_GENERATIONS_COUNT; i++) {
- generations[i].index = i;
- generations[i].current_space = make_space(i);
- generations[i].other_space = make_space(i);
- generations[i].last_size = 0;
- generations[i].self_count = 0;
- generations[i].age_count = 0;
- }
- heap_is_initialized++;
- }
- /* this adds AREA to the "known" heap. Used by find_all for example. */
- void s48_integrate_area(Area* area) {
- Space* space = generations[0].current_space;
- Area** a;
- /* put it behind the first area of the large or small list of the
- first generation */
- if ((area->frontier - area->start) < S48_SMALL_OBJECT_LIMIT) {
- if (space->small_area == NULL)
- a = &space->small_area;
- else
- a = &space->small_area->next;
- } else {
- if (space->large_area == NULL)
- a = &space->large_area;
- else
- a = &space->large_area->next;
- }
- area->generation_index = 0;
- area->next = *a;
- *a = area;
- }
- #if (S48_ADJUST_WATER_MARK)
- static unsigned long aging_space_survival;
- static float last_aging_space_survival = 0; /* initial value does not
- matter */
- static void adjust_water_mark(float aging_space_survival) {
- /* the easies solution would be to set the water-mark according to
- this survival-percent value, but let's try to get some
- convergence. And we tried to weaken extreme values */
- last_aging_space_survival = ((aging_space_survival
- + (gc_count * last_aging_space_survival)) /
- (gc_count + 1));
- /* maybe take int_max(gc_count, 1000) or something... */
- current_water_mark =
- BYTES_TO_PAGES((unsigned long)
- (PAGES_TO_BYTES_I_KNOW_THIS_CAN_OVERFLOW(S48_CREATION_SPACE_SIZE)
- * last_aging_space_survival));
- /* if the water-mark would be at the top, then nothing would be
- copied into the aging_space, and we could not adjust the
- water-mark in the future. */
- if (current_water_mark == S48_CREATION_SPACE_SIZE)
- current_water_mark--;
- }
- #endif
- /********************************************************************
- Starting a Collection
- ********************************************************************/
- #define BROKEN_HEART_P S48_STOB_P
- static unsigned long calc_generation_area_size(Generation* g);
- static unsigned long calc_creation_space_size(CreationSpace* c);
- static long heap_size_count;
- static void heap_size_step(s48_address start, s48_address end) {
- heap_size_count += end - start;
- }
- long s48_heap_size() {
- int i;
- unsigned long size = 0;
- for (i=0; i < S48_GENERATIONS_COUNT; i++){
- size += calc_generation_area_size(&generations[i]);
- }
- size += calc_creation_space_size(&creation_space);
- return size;
- }
- static unsigned long calc_creation_space_size(CreationSpace* c) {
- unsigned long size = 0;
- FOR_ALL_AREAS(c->large,
- size += (area->end - area->start));
- FOR_ALL_AREAS(c->small_below,
- size += (area->end - area->start));
- FOR_ALL_AREAS(c->small_above,
- size += (area->end - area->start));
- FOR_ALL_AREAS(c->weaks,
- size += (area->end - area->start));
- return size;
- }
- /* calc the WHOLE allocated heap (Semispace) */
- static unsigned long calc_generation_area_size(Generation* g) {
- unsigned long size = 0;
- FOR_ALL_AREAS(g->current_space->small_area,
- size += (area->end - area->start));
- FOR_ALL_AREAS(g->current_space->large_area,
- size += (area->end - area->start));
- FOR_ALL_AREAS(g->current_space->weaks_area,
- size += (area->end - area->start));
- return size;
- }
- long s48_heap_live_size() {
- heap_size_count = 0;
- s48_walk_heap(&heap_size_step);
- return heap_size_count;
- }
- /* An extant is either not a stored object, or it has a forwarding
- pointer, or it is in an area that is not currently being collected.
- */
- char s48_extantP(s48_value thing) {
- if ((!S48_STOB_P(thing)) || BROKEN_HEART_P(S48_STOB_HEADER(thing))) {
- return (0 == 0);
- } else {
- Area* area = s48_memory_map_ref(S48_ADDRESS_AT_HEADER(thing));
- return ( (area == NULL) || (GC_ACTION_IGNORE == area->action) );
- }
- }
- static void clean_weak_pointers(Area* areas) {
- while (areas != NULL) {
- s48_address end = areas->frontier;
- s48_address addr = S48_ADDRESS_INC(areas->start);
- for (; addr < end; addr += S48_CELLS_TO_A_UNITS(2)) {
- s48_value stob = *((s48_value*)addr);
- if (!s48_extantP(stob))
- *((s48_value*)addr) = S48_FALSE;
- else {
- /* maybe the object location has changed */
- if (S48_STOB_P(stob) && BROKEN_HEART_P(S48_STOB_HEADER(stob)))
- *((s48_value*)addr) = S48_STOB_HEADER(stob);
- }
- }
- areas = areas->next;
- }
- }
- static void set_targets(Space* space, Space* target) {
- FOR_ALL_AREAS(space->small_area, area->target_space = target);
- FOR_ALL_AREAS(space->large_area, area->target_space = target);
- FOR_ALL_AREAS(space->weaks_area, area->target_space = target);
- }
- /* forward declaration */
- static unsigned long calc_areas_number(Area* next_area);
- #define FOR_YOUNG_AREAS(areas, command) \
- do { \
- Area* area = areas; \
- unsigned long count; \
- unsigned long areas_number; \
- unsigned long old_areas; \
- count = 0; \
- areas_number = calc_areas_number(areas); \
- old_areas = areas_number / S48_PART_OF_OLD_AREAS ; \
- while (area != NULL) { \
- Area* next = area->next; \
- if (count > old_areas) command; \
- count++; \
- area = next; \
- } \
- } while(0)
- /* The youngest areas will be recycled in the same generation*/
- static void reset_young_targets(Space* space, Space* target) {
- FOR_YOUNG_AREAS(space->small_area, area->target_space = target);
- /* Large Objects should be allways promoted as they are */
- /* FOR_YOUNG_AREAS(space->large_area, area->target_space = target); */
- FOR_YOUNG_AREAS(space->weaks_area, area->target_space = target);
- }
- static void set_gc_actions(Space* space, gc_action_t small,
- gc_action_t large, gc_action_t weaks) {
- FOR_ALL_AREAS(space->small_area, area->action = small);
- FOR_ALL_AREAS(space->large_area, area->action = large);
- FOR_ALL_AREAS(space->weaks_area, area->action = weaks);
- }
- /* How many Area(s) are in the linked listz of areas */
- static unsigned long calc_areas_number(Area* next_area){
- unsigned long the_areas_number=0;
-
- while (next_area){
- the_areas_number++;
- next_area = next_area->next;
- }
- #if (BIBOP_LOG)
- s48_bibop_log("Areas Number: %i", the_areas_number);
- #endif
- return the_areas_number;
- }
- /* calc only the used heap (Semispace) */
- static unsigned long calc_generation_size(Generation* g) {
- unsigned long size = 0;
- FOR_ALL_AREAS(g->current_space->small_area,
- size += (area->frontier - area->start));
- FOR_ALL_AREAS(g->current_space->large_area,
- size += (area->frontier - area->start));
- FOR_ALL_AREAS(g->current_space->weaks_area,
- size += (area->frontier - area->start));
- return size;
- }
- static unsigned long calc_generation_other_space_size(Generation* g) {
- unsigned long size = 0;
- FOR_ALL_AREAS(g->other_space->small_area,
- size += (area->frontier - area->start));
- FOR_ALL_AREAS(g->other_space->large_area,
- size += (area->frontier - area->start));
- FOR_ALL_AREAS(g->other_space->weaks_area,
- size += (area->frontier - area->start));
- return size;
- }
- /* FPage 6 - 7 - 8 */
- inline static void init_areas(int count) {
- int i, current_target,
- creation_space_target_small_below_generation_index,
- creation_space_target_generation_index;
- unsigned long current_size;
- /* Generation indices for the creation_space */
- #if (S48_GENERATIONS_COUNT > 1)
- creation_space_target_small_below_generation_index = 1;
- #else
- creation_space_target_small_below_generation_index = 0;
- #endif
- creation_space_target_generation_index = 0;
- /* REMARK: At the very first collection, the image is loaded, which
- has source compiled code that rarely changes. At this point there
- was no execution of the main program yet. We can hold the
- surviving objects of the first collection (of the creation_space
- or of the first generation - or both) in a protected generation
- (preferrably the oldest one) which is collected never again.
- (alternatively collecting it after a large number of collections)
- For this purpose we need at least 3 generations! The option to
- activate this is S48_USE_STATIC_SPACE */
- #if (S48_USE_STATIC_SPACE)
- if (s48_gc_count() == 0) {
- creation_space_target_small_below_generation_index = S48_GENERATIONS_COUNT - 1;
- creation_space_target_generation_index = creation_space_target_small_below_generation_index;
- }
- #endif
- /* FPage 6 */
- /* initialize the creation_space */
- /* the objects of the small_below area that will survive the
- collection will be moved into an older generation */
- if (creation_space.small_below != NULL) {
- assert(creation_space.small_below->next == NULL);
- creation_space.small_below->target_space =
- generations[creation_space_target_small_below_generation_index].current_space;
- creation_space.small_below->action = GC_ACTION_COPY_SMALL;
- }
- /* the objects of the small_above area, large area and weaks area,
- that will survive the collection will be moved (or marked) into
- the youngest (first) generation, to be soon recollected */
- if (creation_space.small_above != NULL) {
- assert(creation_space.small_above->next == NULL);
- creation_space.small_above->target_space =
- generations[creation_space_target_generation_index].current_space;
- creation_space.small_above->action = GC_ACTION_COPY_SMALL;
- }
-
- assert(creation_space.weaks->next == NULL);
- creation_space.weaks->target_space = generations[creation_space_target_generation_index].current_space;
- creation_space.weaks->action = GC_ACTION_COPY_WEAK;
-
- FOR_ALL_AREAS(creation_space.large,
- area->target_space = generations[creation_space_target_generation_index].current_space;
- area->action = GC_ACTION_MARK_LARGE );
-
- /* FPage 7 */
- /* Promotion policy - Which generation should the live objects be
- copied to? */
- #if (BIBOP_LOG)
-
- /* all current sizes */
- #if (S48_PROMOTION_THRESHOLD)
- s48_bibop_log("S48_PROMOTION_THRESHOLD: %i", S48_PROMOTION_THRESHOLD);
- #endif
-
- #if (S48_PROMOTION_HEAP_LIMIT)
- s48_bibop_log("S48_PROMOTION_HEAP_LIMIT: %i", S48_PROMOTION_HEAP_LIMIT);
- #endif
-
- #if (S48_PROMOTION_AGE_LIMIT)
- s48_bibop_log("S48_PROMOTION_AGE_LIMIT: %i", S48_PROMOTION_AGE_LIMIT);
- #endif
-
- for (i = S48_GENERATIONS_COUNT - 1; i > -1; i--) {
- /* Look out! Spaces are allready swapped !!! */
- current_size = calc_generation_other_space_size(&generations[i]);
-
- #if (S48_PROMOTION_THRESHOLD)
- s48_bibop_log("Generation %i : %i ", i, (current_size - generations[i].last_size));
- #endif
-
- #if (S48_PROMOTION_HEAP_LIMIT)
- s48_bibop_log("Generation %i : %i ", i, current_size);
-
- #endif
-
- #if (S48_PROMOTION_AGE_LIMIT)
- s48_bibop_log("Generation %i : Age Count %i ", i, generations[i].age_count);
- s48_bibop_log("Generation %i : Self Count %i ", i, generations[i].self_count);
- #endif
- }
- #endif /* #if (BIBOP_LOG) */
-
-
- /* initialize the areas that will be collected. */
- for (i = 0; i < count; i++) {
- /* trace everything */
- FOR_ALL_AREAS(generations[i].current_space->small_area,
- area->trace = area->start);
- FOR_ALL_AREAS(generations[i].current_space->large_area,
- area->trace = area->start);
-
- /* targets of the other_spaces are the current_space of the choosen
- generation according to the promotion option */
-
- /* Look out! Spaces are allready swapped !!! */
- current_size = calc_generation_other_space_size(&generations[i]);
-
- #if (S48_PROMOTION_THRESHOLD)
-
- current_target = ( (current_size - generations[i].last_size)
- > S48_PROMOTION_THRESHOLD)
- ? i + 1
- : i;
-
- #elif (S48_PROMOTION_HEAP_LIMIT)
- /* Look out! Spaces are allready swapped !!! */
- current_target = (current_size > S48_PROMOTION_HEAP_LIMIT)
- ? i + 1
- : i;
-
- #elif (S48_PROMOTION_AGE_LIMIT)
- current_target = (generations[i].self_count > 0 &&
- generations[i].self_count % S48_PROMOTION_AGE_LIMIT == 0)
- ? i + 1
- : i;
-
- #else
- #error "BIBOP GC configuration error: no promotion policy defined"
- #endif
- #if (S48_USE_STATIC_SPACE)
- current_target = (s48_gc_count() == 0) ? creation_space_target_small_below_generation_index : current_target ;
- #endif
-
- /* Adjust index j (for the last generation) */
- #if (S48_USE_STATIC_SPACE)
- current_target = (current_target >= S48_GENERATIONS_COUNT - 1) ? S48_GENERATIONS_COUNT - 2 : current_target ;
- #else
- current_target = (current_target >= S48_GENERATIONS_COUNT) ? S48_GENERATIONS_COUNT - 1 : current_target ;
- #endif
-
- /* promotion targets */
- set_targets(generations[i].other_space, generations[current_target].current_space);
- /* Wilson's opportunistic object promotion targets */
- if ( i != current_target ) {
- reset_young_targets(generations[i].other_space,
- generations[i].current_space);
- }
- #if (BIBOP_LOG)
- s48_bibop_log("generations[%i].other_space -> generations[%i].current_space",
- i, current_target);
- #endif
- /* actions: the ones that will be evacuated now */
- set_gc_actions(generations[i].other_space, GC_ACTION_COPY_SMALL,
- GC_ACTION_MARK_LARGE, GC_ACTION_COPY_WEAK);
- /* ignore the ones that will be filled now */
- set_gc_actions(generations[i].current_space, GC_ACTION_IGNORE,
- GC_ACTION_IGNORE, GC_ACTION_IGNORE);
- }
-
- /* FPage 8 */
- /* initialize the areas that are not collected this time */
- for (i = count; i < S48_GENERATIONS_COUNT; i++) {
- /* trace only what will be added to these */
- /* maybe only the first "old" one will have to be traced ?? */
- FOR_ALL_AREAS(generations[i].current_space->small_area,
- area->trace = area->frontier);
- FOR_ALL_AREAS(generations[i].current_space->large_area,
- area->trace = area->frontier);
-
- /* the other spaces should be empty anyway */
- set_gc_actions(generations[i].other_space, GC_ACTION_ERROR,
- GC_ACTION_ERROR, GC_ACTION_ERROR);
- set_gc_actions(generations[i].current_space, GC_ACTION_IGNORE,
- GC_ACTION_IGNORE, GC_ACTION_IGNORE);
- }
- }
- inline static void clear_space(Space* space) {
- FOR_ALL_AREAS(space->small_area, s48_free_area(area)); space->small_area = NULL;
- FOR_ALL_AREAS(space->large_area, s48_free_area(area)); space->large_area = NULL;
- FOR_ALL_AREAS(space->weaks_area, s48_free_area(area)); space->weaks_area = NULL;
- }
- static char trace_areas(Area* areas) {
- char hit = 0;
- while (areas != NULL) {
- while (1) {
- s48_address start = areas->trace;
- s48_address end = areas->frontier;
- if (start != end) {
- s48_internal_trace_locationsB(areas, TRUE, start, end, "trace_areas");
- areas->trace = end;
- hit = 1;
- } else
- break;
- }
- areas = areas->next;
- }
-
- return hit;
- }
- static void do_gc() {
- char hit;
- do {
- int i;
- char hit0, hit1;
- hit = FALSE;
- /* maybe it's enough to trace up to max_gen+1 */
- for (i = 0; i < S48_GENERATIONS_COUNT; i++) {
- hit0 = trace_areas(generations[i].current_space->small_area);
- hit1 = trace_areas(generations[i].current_space->large_area);
- hit = hit0 || hit1 || hit;
- }
- } while ( hit );
- }
- inline static void swap(Generation* g) {
- Space* tmp = g->current_space;
- g->current_space = g->other_space;
- g->other_space = tmp;
- }
- #if (MEASURE_GC)
- /* We include this here, because the measurement code uses static
- variables from here a lot */
- #include "measure.ci"
- #endif
- long s48_gc_count() {
- return gc_count;
- }
- long s48_gc_run_time(long* mseconds) {
- *mseconds = gc_mseconds;
- return gc_seconds;
- }
- /* collect the first COUNT generations */
- /* FPage 5 ... */
- static void collect(int count, psbool emergency) {
- int i;
- #if (S48_USE_STATIC_SPACE)
- psbool major_p = (count == (S48_GENERATIONS_COUNT - 1));
- #else
- psbool major_p = (count == S48_GENERATIONS_COUNT);
- #endif
- /* this it for the water mark changing at the end of the collection */
- #if (S48_ADJUST_WATER_MARK)
- aging_space_survival = 0;
- aging_space_before = 0;
- FOR_ALL_AREAS(generations[0].current_space->small_area,
- aging_space_before += (area->frontier - area->start));
- #endif
- /* swap spaces and update age_count first */
- /* FPage 5 */
- for (i = 0; i < count; i++) {
- swap(&generations[i]);
- generations[i].age_count++;
-
- #if (BIBOP_LOG)
- s48_bibop_log("swapped current <-> other generation %i", i);
- #endif
- }
- /* update self_count for the generation from wich the collection
- starts */
- generations[count-1].self_count++;
- /* Initialize actions, targets and trace pointers */
- /* FPage 6 - 7 - 8 */
- init_areas(count);
- /* trace all roots to the younger generations */
- #if (S48_USE_REMEMBERED_SETS)
- for (i = 0; i < count; i++) {
- RemSet* rs; RemSet* nrs;
- FOR_ALL_AREAS(generations[i].other_space->small_area,
- s48_trace_remset(area->remset));
- FOR_ALL_AREAS(generations[i].other_space->weaks_area,
- s48_trace_remset(area->remset));
- /* beause large areas are "reused", the remembered set has to be
- freed explicitly */
- FOR_ALL_AREAS(generations[i].other_space->large_area,
- nrs = s48_make_remset();
- rs = area->remset;
- area->remset = nrs;
- s48_trace_remset(rs);
- s48_free_remset(rs);
- );
- }
- #endif
- /* FPage 9 ... */
- for (i = count; i < S48_GENERATIONS_COUNT; i++) {
- #if (BIBOP_LOG)
- s48_bibop_log("Tracing roots from current-space of generation %i\n", i);
- #endif
- /* FPage 9 ... area_roots.c */
- s48_trace_areas_roots(generations[i].current_space->small_area);
- s48_trace_areas_roots(generations[i].current_space->large_area);
- }
- s48_gc_root();
- /* do the tracing until everything is done */
- do_gc();
- /* clean up*/
- for (i = 0; i < S48_GENERATIONS_COUNT; i++) {
- clean_weak_pointers(generations[i].current_space->weaks_area);
- }
- s48_post_gc_cleanup(major_p, emergency);
- /* for objects resurrected in some post-gc-cleanup, trace again */
- do_gc();
- for (i = 0; i < count; i++) {
- clear_space(generations[i].other_space);
- generations[i].last_size = calc_generation_size(&generations[i]);
- }
- /* reset creation space */
- #if (S48_ADJUST_WATER_MARK)
- if (aging_space_before != 0)
- adjust_water_mark((float)aging_space_survival / aging_space_before);
- #endif
- recreate_creation_space();
- gc_count++;
- }
- static psbool do_collect(psbool force_major, psbool emergency);
- /* FPage 4 - 5 */
- void s48_collect(psbool force_major) {
- /*
- The BIBOP GC's heap gets an absolute maximal size with the -h flag
- of scheme48.
- -h <heap_size> : means <heap_size> cells (0 means no size limit).
- Without the -h flag, the heap size gets a default value
- (init.c). We have to calculate a minimal heap size, set by the
- special configuration of BIBOP (gc_config.h), to decide during the
- initialization (s48_initialize_bibop_heap()) if the given
- <heap_size> is reasonable or not. This is done after the
- allocation of the image_areas (s48_initialize_image_areas()). If
- the maximal heap size is too small we increase it to a reasonable
- value (the user is informed about that).
-
- The variable 'actual_heap_size' (in cells) is updated before each
- collection and represents the total size of all used areas (but
- without allocated free areas, and without the memory used for the
- various structures like Area, Metapage, Generation etc.). If this
- actual heap size rises above the user defined (or default) maximal
- heap size, we halt the program.
- */
- unsigned long user_defined_hsize, heap_live_size;
- psbool was_major;
- long start_seconds, start_mseconds, end_seconds, end_mseconds;
- start_seconds = s48_run_time(&start_mseconds);
- was_major = do_collect(force_major, FALSE);
- heap_live_size = S48_BYTES_TO_CELLS(s48_heap_live_size());
- user_defined_hsize = s48_max_heap_size();
- if ((user_defined_hsize > 0) &&
- (heap_live_size > (user_defined_hsize *
- ((100.0 - S48_EMERGENCY_PERCENTAGE)/100.0)))) {
- /* try again with a major collection. If it's still too much
- afterwards, quit. */
- if (! was_major)
- do_collect(TRUE, TRUE);
- heap_live_size = S48_BYTES_TO_CELLS(s48_heap_live_size());
- if (heap_live_size > user_defined_hsize)
- s48_gc_error("Scheme 48 heap overflow (max heap size %i cells)\n",
- user_defined_hsize);
- }
- end_seconds = s48_run_time(&end_mseconds);
- if (end_mseconds >= start_mseconds) {
- gc_seconds = gc_seconds + (end_seconds - start_seconds);
- gc_mseconds = gc_mseconds + (end_mseconds - start_mseconds);
- }
- else {
- gc_seconds = gc_seconds + ((end_seconds - start_seconds) - 1);
- gc_mseconds = gc_mseconds + ((1000 + end_mseconds) - start_mseconds);
- }
- }
- static psbool do_collect(psbool force_major, psbool emergency) {
- /* Which generations should be collected? */
- /* collect up to the oldest generation that has grown enough since
- its last collection. */
- /* The youngest generation is collected always */
- /* FPage 5 */
- int c; /* generation number */
- #if (BIBOP_LOG)
- /* all current sizes */
- #if (S48_COLLECTION_THRESHOLD)
- s48_bibop_log("S48_COLLECTION_THRESHOLD: %i", S48_COLLECTION_THRESHOLD);
- #endif
- #if (S48_COLLECTION_HEAP_LIMIT)
- s48_bibop_log("S48_COLLECTION_HEAP_LIMIT: %i", S48_COLLECTION_HEAP_LIMIT);
- #endif
- #if (S48_COLLECTION_AGE_LIMIT)
- s48_bibop_log("S48_COLLECTION_AGE_LIMIT: %i", S48_COLLECTION_AGE_LIMIT);
- #endif
- { int i;
- for (i = S48_GENERATIONS_COUNT - 1; i > -1; i--) {
- unsigned long current_size;
- current_size = calc_generation_size(&generations[i]);
- #if (S48_COLLECTION_THRESHOLD)
- s48_bibop_log("Generation %i : %i ", i, (current_size - generations[i].last_size));
- #endif
- #if (S48_COLLECTION_HEAP_LIMIT)
- s48_bibop_log("Generation %i : %i ", i, current_size);
- #endif
- #if (S48_COLLECTION_AGE_LIMIT)
- s48_bibop_log("Generation %i : %i ", i, generations[i].age_count);
- #endif
- }}
- #endif /* #if (BIBOP_LOG) */
-
- /* Which generation should be collected? */
- #if (S48_USE_STATIC_SPACE)
- c = S48_GENERATIONS_COUNT - 1;
- #else
- c = S48_GENERATIONS_COUNT;
- #endif
- if (! force_major) {
- for (; c > 1; c--) {
- unsigned long current_size;
- current_size = calc_generation_size(&generations[c-1]);
-
- #if (S48_COLLECTION_THRESHOLD)
- if ((current_size - generations[c-1].last_size) > S48_COLLECTION_THRESHOLD)
- break;
- #endif
- #if (S48_COLLECTION_HEAP_LIMIT)
- if (current_size > S48_COLLECTION_HEAP_LIMIT)
- break;
- #endif
- #if (S48_COLLECTION_AGE_LIMIT)
- if (generations[c-1].self_count > 0 &&
- generations[c-1].self_count % S48_COLLECTION_AGE_LIMIT == 0)
- break;
- #endif
- }
- }
- #if (BIBOP_LOG)
- s48_bibop_log("Generation choosen: %i", c-1);
- s48_bibop_log("Starting Collection...");
- #endif
- #if (MEASURE_GC)
- measure_before_collection(c);
- #endif
- /*************************************/
- /* Now is going to be really collected */
- /* FPage 5 ... */
- collect(c, emergency);
- /*************************************/
- #if (MEASURE_GC)
- measure_after_collection(c);
- #endif
- #if (BIBOP_LOG)
- s48_bibop_log("Collection done!");
- #endif
- #if (S48_USE_STATIC_SPACE)
- return (c == S48_GENERATIONS_COUNT-1);
- #else
- return (c == S48_GENERATIONS_COUNT);
- #endif
- }
- /*********************************************************************
- Tracing
- ********************************************************************/
- /* forward declarations */
- inline static void mark_large(Area* area, Space* to_space);
- inline static Area* allocate_small_area(Space* space,
- unsigned long size_in_bytes);
- inline static Area* allocate_weak_area(Space* space);
- inline static Area* allocate_large_area(Space* space,
- unsigned long size_in_bytes);
- /* the value STOB has been written to location ADDR */
- inline static void call_internal_write_barrier(Area* maybe_area, char area_looked_up, s48_address addr,
- s48_value stob, Area* to_area) {
- if (!area_looked_up) maybe_area = s48_memory_map_ref(addr);
- /* if maybe_area is still NULL, it must have been a write to a
- location outside of the heap, e.g. a temporary pointer or
- something in the root-set; we can ignore it. */
- if ((maybe_area != NULL) && (maybe_area->generation_index > 0))
- s48_internal_write_barrier(maybe_area, addr, stob, to_area);
- }
- inline static void call_internal_write_barrier2(Area* maybe_area, char area_looked_up, s48_address addr,
- s48_value stob) {
- call_internal_write_barrier(maybe_area, area_looked_up, addr, stob,
- s48_memory_map_ref(S48_ADDRESS_AT_HEADER(stob)));
- }
- #if (S48_HAVE_TRANSPORT_LINK_CELLS)
- static Area* make_small_available_in_no_gc(Space* space,
- unsigned long size_in_bytes) {
- Area* area = space->small_area;
- if (size_in_bytes > AREA_REMAINING(area)) {
- area = allocate_small_area(space, size_in_bytes);
- }
- return area;
- }
- static s48_address allocate_small_in_no_gc(Space* space,
- unsigned long size_in_bytes) {
- Area* area = make_small_available_in_no_gc(space, size_in_bytes);
- s48_address addr = area->frontier;
- area->frontier += S48_BYTES_TO_A_UNITS(size_in_bytes);
- return addr;
- }
- static s48_value make_stob(long type, unsigned long size_in_cells) {
- /* Must work during a collection! */
- unsigned long size_in_bytes = S48_CELLS_TO_BYTES(size_in_cells);
- /* Allocate a place for it */
- s48_address addr = allocate_small_in_no_gc(
- generations[0].current_space,
- S48_STOB_OVERHEAD_IN_BYTES + size_in_bytes);
- /* Initialize */
- assert(S48_STOB_OVERHEAD_IN_BYTES == sizeof(s48_value));
- *((s48_value*)addr) = S48_MAKE_HEADER(type, size_in_bytes);
- memset(addr + S48_STOB_OVERHEAD_IN_A_UNITS, 0, size_in_bytes);
- return S48_ADDRESS_TO_STOB_DESCRIPTOR(addr + S48_STOB_OVERHEAD_IN_A_UNITS);
- }
- static s48_value make_pair(s48_value car, s48_value cdr) {
- s48_value result = make_stob(S48_STOBTYPE_PAIR, 2);
- S48_UNSAFE_SET_CAR(result, car);
- S48_UNSAFE_SET_CDR(result, cdr);
- return result;
- }
- static void append_tconcB(s48_value tconc, s48_value elem) {
- /* A tconc is a pair, whose car points to the first pair of a list
- and whose cdr points to the last pair of this list. */
- /* elem must already be in the "to space"! */
- s48_value tconc_tail = S48_UNSAFE_CDR(tconc);
- assert(S48_PAIR_P(tconc));
- /* Though the tconc must already be in the "to space", it's cdr (and
- car) could still point to the "from space". But that does not
- matter here, because if it still has to be copied, it's (already
- correct) contents will be ignored in the tracing. And because we
- only write pointers to objects in the "to space", nothing has to
- be traced additionally here. */
- if (S48_PAIR_P(tconc_tail)) {
- /* create a new pair */
- s48_value newpair = make_pair(S48_FALSE, S48_FALSE);
-
- /* enqueue the tlc (=elem) in the tconc queue */
- S48_UNSAFE_SET_CAR(tconc_tail, elem);
- S48_UNSAFE_SET_CDR(tconc_tail, newpair);
- S48_UNSAFE_SET_CDR(tconc, newpair); /* new tail */
- }
- /* else: silently ignoring malformed tconc */
- }
- static void trace_transport_link_cell(Area* maybe_area, char area_looked_up,
- s48_address contents_pointer,
- unsigned long size_in_a_units) {
- s48_value tlc = S48_ADDRESS_TO_STOB_DESCRIPTOR(contents_pointer);
- s48_value old_key;
- char key_moved_p;
- assert(S48_TRANSPORT_LINK_CELL_P(tlc));
- old_key = S48_UNSAFE_TRANSPORT_LINK_CELL_KEY(tlc);
- /* ...trace the current tlc to make sure that every pointer is up-to-date. */
- s48_internal_trace_locationsB(
- maybe_area, area_looked_up, contents_pointer,
- contents_pointer + size_in_a_units,
- "trace_transport_link_cell");
- /* Hint: We will not recognize large keys "moving" into an older
- generation; but the tlc-logic is only interested in keys changing
- their address anyway. So that does not matter */
- key_moved_p = (S48_UNSAFE_TRANSPORT_LINK_CELL_KEY(tlc) != old_key);
- if (key_moved_p) {
- s48_value tconc = S48_UNSAFE_TRANSPORT_LINK_CELL_TCONC(tlc);
- /* If the tconc field is a pair... */
- if (S48_FALSE_P(tconc))
- {} /* ignore */
- else if (S48_PAIR_P(tconc)
- && S48_PAIR_P(S48_UNSAFE_CAR(tconc))
- && S48_PAIR_P(S48_UNSAFE_CDR(tconc))) {
- /* ...then add the tlc to the end of the tconc queue. */
- append_tconcB(tconc, tlc);
- /* ...and set the tconc field to null (false). */
- S48_UNSAFE_SET_TRANSPORT_LINK_CELL_TCONC(tlc, S48_FALSE);
- }
- else
- {} /*printf("Warning: malformed tlc at %p.\n", S48_ADDRESS_AT_HEADER(tlc));*/
- }
- assert(S48_TRANSPORT_LINK_CELL_P(tlc));
- }
- #endif /* S48_HAVE_TRANSPORT_LINK_CELLS */
- /* EKG checks for broken hearts - only used internally in
- s48_trace_locationsB */
- #define EKG(label) {\
- long header = S48_STOB_HEADER(trace_stob_stob);\
- if (BROKEN_HEART_P((s48_value)header)) {\
- *((s48_value*)addr) = header;\
- call_internal_write_barrier2(maybe_area, area_looked_up, addr, \
- (s48_value)header);\
- addr = next;\
- goto loop;\
- } else {\
- copy_header = header;\
- copy_thing = trace_stob_stob;\
- goto label;\
- }\
- }
- void do_copy_object(s48_address addr, /* addr of pointer */
- Area * maybe_area, /* laying in area, if known */
- char area_looked_up, /* area known? */
- Area * from_area, /* pointing in area */
- s48_value copy_thing, /* stob descriptor */
- s48_value copy_header, /* stob header */
- Area * copy_area /* target area */
- ) {
- /* we start writing at the frontier location */
- s48_address frontier = copy_area->frontier;
- /* the data, means after the header, will be written at this location */
- s48_address data_addr = frontier + S48_STOB_OVERHEAD_IN_A_UNITS;
- /* Since the s48_address is allways 4 bytes, the lower 2 bits are allways 00 */
- /* We use these 2 bits for the STOB-TAG: 11 to make a scheme-stob */
- s48_value new = S48_ADDRESS_TO_STOB_DESCRIPTOR(data_addr);
- assert(s48_memory_map_ref(S48_ADDRESS_AT_HEADER(new)) == copy_area);
- #if (S48_ADJUST_WATER_MARK)
- /* count small object-sizes, that survive in the first generation */
- if ((from_area->generation_index == 0) &&
- (from_area != creation_space.small_below) &&
- (from_area != creation_space.small_above) &&
- (from_area->action == GC_ACTION_COPY_SMALL))
- aging_space_survival += S48_HEADER_LENGTH_IN_A_UNITS(copy_header) +
- S48_STOB_OVERHEAD_IN_BYTES;
- #endif
- /* count every surviving obj */
- #if (MEASURE_GC)
- all_surviving_obj += S48_HEADER_LENGTH_IN_A_UNITS(copy_header) +
- S48_STOB_OVERHEAD_IN_BYTES;
- #endif
- /* copy the object to the new location */
- /* first the header at the frontier location */
- *((s48_value*)frontier) = copy_header;
- /* and then the data (thing addresss after header) at the data_addr
- location */
- assert(AREA_REMAINING(copy_area) >= (S48_HEADER_LENGTH_IN_BYTES(copy_header)
- + S48_STOB_OVERHEAD_IN_BYTES));
-
- memcpy((void*)data_addr, S48_ADDRESS_AFTER_HEADER(copy_thing, void),
- S48_HEADER_LENGTH_IN_BYTES(copy_header));
- /* break heart */
- /* alternative: S48_STOB_HEADER(copy_thing) = new;*/
- *((s48_value*)S48_ADDRESS_AT_HEADER(copy_thing)) = new;
- /* advance the allocation pointer */
- copy_area->frontier = data_addr + S48_HEADER_LENGTH_IN_A_UNITS(copy_header);
- /* overwrite the old stob with the new one */
- *((s48_value*)addr) = new;
- /* if we are tracing an area of an older generation call write_barrier */
- call_internal_write_barrier(maybe_area, area_looked_up, addr, new, copy_area);
- }
- /* Copy everything pointed to from somewhere between START (inclusive)
- and END (exclusive).
- */
- void s48_internal_trace_locationsB(Area* maybe_area, char area_looked_up, s48_address start,
- s48_address end, char* called_from) {
- s48_address addr = start;
- s48_address next;
- s48_value thing;
- s48_value trace_stob_stob;
- long copy_header;
- s48_value copy_thing;
- Area* copy_area;
- Area* from_area;
- Space* copy_to_space;
- loop: {
- if (addr < end) {
- thing = *((s48_value*) addr);
- next = S48_ADDRESS_INC(addr);
- if (S48_HEADER_P(thing)) {
- if (S48_B_VECTOR_HEADER_P(thing)) {
- addr = next + S48_HEADER_LENGTH_IN_A_UNITS(thing);
- }
- else if (S48_HEADER_TYPE(thing) == S48_STOBTYPE_CONTINUATION) {
- long size = S48_HEADER_LENGTH_IN_A_UNITS(thing);
- extern void s48_trace_continuation(char *, long); /* BIBOP-specific */
- s48_trace_continuation(next, size);
- addr = next + size;
- }
- #if (S48_HAVE_TRANSPORT_LINK_CELLS)
- else if (S48_HEADER_TYPE(thing) == S48_STOBTYPE_TRANSPORT_LINK_CELL) {
- long size = S48_HEADER_LENGTH_IN_A_UNITS(thing);
- trace_transport_link_cell(maybe_area, area_looked_up, next, size);
- addr = next + size;
- }
- #endif
- else {
- addr = next;
- }
- goto loop;
- } else if (! S48_STOB_P(thing)) {
- addr = next;
- goto loop;
- } else {
- /* it's a stob */
- trace_stob_stob = thing;
- goto trace_stob;
- }
- }
- return;
- }
- trace_stob: { /* parameter: trace_stob_stob */
- from_area = s48_memory_map_ref(S48_ADDRESS_AT_HEADER(trace_stob_stob));
- if (from_area != NULL) {
- switch (from_area->action) {
- case GC_ACTION_COPY_SMALL: {
- copy_to_space = from_area->target_space;
- EKG(copy_small);
- } break;
- case GC_ACTION_COPY_MIXED: {
- copy_to_space = from_area->target_space;
- EKG(copy_mixed);
- } break;
- case GC_ACTION_COPY_WEAK: {
- copy_to_space = from_area->target_space;
- EKG(copy_weak_pointer);
- } break;
- case GC_ACTION_IGNORE: {
- call_internal_write_barrier(maybe_area, area_looked_up, addr, trace_stob_stob, from_area);
- addr = next;
- goto loop;
- } break;
- case GC_ACTION_MARK_LARGE: {
- copy_to_space = from_area->target_space;
- mark_large(from_area, copy_to_space);
- /* a large object has been "copied" */
- call_internal_write_barrier(maybe_area, area_looked_up, addr, trace_stob_stob, from_area);
- addr = next;
- goto loop;
- } break;
- case GC_ACTION_ERROR: {
- s48_gc_error("got error gc-action in the %i generation", from_area->generation_index + 1);
- return; /* Never reached */
- } break;
- default: {
- s48_gc_error("got unexpected gc-action %d in the %i generation", from_area->action, from_area->generation_index + 1);
- return; /* Never reached */
- }
- }
- }
- else {
- s48_gc_error("illegal stob descriptor found while tracing address %p called from %s",
- addr, called_from);
- return; /* Never reached */
- }
- }
-
- assert(FALSE); /* we should never get here */
- /* Find out which is the actual copy_area for small, large, etc. object */
- copy_small: { /* parameter: copy_to_space, copy_header, copy_thing */
- /* get the current Area of the copy_space, means target_space */
- Area* area = copy_to_space->small_area;
- unsigned long size_in_bytes = (S48_HEADER_LENGTH_IN_A_UNITS(copy_header)
- + S48_STOB_OVERHEAD_IN_A_UNITS);
- if (size_in_bytes <= AREA_REMAINING(area))
-
- /* If the object fits then this is the copy_area ...*/
- copy_area = area;
- else
- /* otherwise, allocate a small area in this space */
- copy_area = allocate_small_area(copy_to_space, size_in_bytes);
- goto copy_object;
- }
- copy_large: { /* parameter: copy_to_space, copy_header, copy_thing */
- copy_area = allocate_large_area( copy_to_space,
- S48_HEADER_LENGTH_IN_BYTES(copy_header) +
- S48_STOB_OVERHEAD_IN_BYTES );
- goto copy_object;
- }
- copy_mixed: { /* parameter: copy_to_space, copy_header, copy_thing */
- if (S48_STOBTYPE_WEAK_POINTER == S48_HEADER_TYPE(copy_header))
- goto copy_weak_pointer; /* uses copy_to_space, copy_thing! */
- else if (S48_HEADER_LENGTH_IN_BYTES(copy_header) < S48_SMALL_OBJECT_LIMIT)
- goto copy_small; /* uses copy_to_space, copy_thing, copy_header! */
- else
- goto copy_large; /* dito */
- }
- copy_weak_pointer: { /* parameter: copy_to_space, copy_thing */
- Area* area = copy_to_space->weaks_area;
- /*copy_header = WEAK_POINTER_HEADER;*/
- if ((unsigned long) (S48_HEADER_LENGTH_IN_A_UNITS(copy_header)
- + S48_STOB_OVERHEAD_IN_A_UNITS)
- < AREA_REMAINING(area))
- copy_area = area;
- else
- copy_area = allocate_weak_area(copy_to_space);
- goto copy_object;
- }
- copy_object: { /* parameter: from_area, copy_thing, copy_header, copy_area */
- do_copy_object(addr, maybe_area, area_looked_up, from_area, copy_thing, copy_header, copy_area);
- /* continue behind that stob */
- addr = next;
- goto loop;
- }
- } /* end: trace_locationsB */
- /* Traces between START (inclusive) and END (exclusive). */
- void s48_trace_locationsB(s48_address start, s48_address end) {
- s48_internal_trace_locationsB(NULL, FALSE, start, end, "s48_trace_locationsB");
- }
- /* s48_trace_value passes the location of STOB to
- s48_trace_locationsB. */
- s48_value s48_trace_value(s48_value stob) {
- s48_address addr = (s48_address)&stob;
- (void)s48_trace_locationsB(addr, S48_ADDRESS_INC(addr));
- /* stob now holds the new location of the value... */
- return stob;
- }
- /* s48_trace_stob_contentsB passes the contents of a d-vector stob to
- s48_trace_locations. Never call this with b-vectors! */
- void s48_trace_stob_contentsB(s48_value stob) {
- s48_address start = (s48_address)S48_ADDRESS_AFTER_HEADER(stob, void);
- unsigned long size = S48_BYTES_TO_A_UNITS(S48_STOB_BYTE_LENGTH(stob));
- s48_trace_locationsB(start, (start + size));
- }
- /* creating new areas during gc */
- inline static Area* allocate_small_area(Space* space,
- unsigned long size_in_bytes) {
- Area* area = s48_allocate_area(ulong_max(S48_MINIMUM_SMALL_AREA_SIZE,
- BYTES_TO_PAGES(size_in_bytes)),
- ulong_max(S48_MAXIMUM_SMALL_AREA_SIZE,
- BYTES_TO_PAGES(size_in_bytes)),
- (unsigned char)space->generation_index,
- AREA_TYPE_SIZE_SMALL);
- area->action = GC_ACTION_IGNORE;
- area->next = space->small_area;
- space->small_area = area;
- return area;
- }
- inline static Area* allocate_large_area(Space* space,
- unsigned long size_in_bytes) {
- unsigned long pages = BYTES_TO_PAGES(size_in_bytes);
- Area* area = s48_allocate_area(pages,
- pages,
- (unsigned char)space->generation_index,
- AREA_TYPE_SIZE_LARGE);
- area->action = GC_ACTION_IGNORE;
- area->next = space->large_area;
- space->large_area = area;
- return area;
- }
- inline static Area* allocate_weak_area(Space* space) {
- Area* area = s48_allocate_area(S48_MINIMUM_WEAK_AREA_SIZE,
- S48_MAXIMUM_WEAK_AREA_SIZE,
- (unsigned char)space->generation_index,
- AREA_TYPE_SIZE_WEAKS);
- area->action = GC_ACTION_IGNORE;
- area->next = space->weaks_area;
- space->weaks_area = area;
- return area;
- }
- /* Remove AREA from from-space's list and put it on to-space's. Ignore
- AREA from now on.
- */
- inline static void delete_large_area(Area* large_area) {
- char hit = FALSE;
- FOR_ALL_AREAS(creation_space.large,
- if (area == large_area) hit = TRUE);
- if (hit)
- creation_space.large = s48_delete_area(creation_space.large, large_area);
- else {
- Space* from_space = generations[large_area->generation_index].other_space;
- from_space->large_area = s48_delete_area(from_space->large_area, large_area);
- }
- }
- inline static void mark_large(Area* area, Space* to_space) {
- delete_large_area(area);
- area->next = to_space->large_area;
- to_space->large_area = area;
- area->action = GC_ACTION_IGNORE;
- area->generation_index = to_space->generation_index;
- area->trace = area->start;
- }
- /*********************************************************************
- Allocation
- *********************************************************************/
- long s48_available() {
- /* it's not 100% sure that all these cells can be allocated, because
- if an object does not fit into area_below, the remaining space is
- discarded. Is this a bad thing ?? */
- /* If the heap can grow, the remaining memory in the creation space
- is available. If it can't, we have to consider, that the actually
- allocated heap (s48_heap_size) cannot grow above
- s48_max_heap_size(). So less space is really available. */
- long max_heap_size = s48_max_heap_size();
- long available_creation_space =
- S48_BYTES_TO_CELLS(AREA_REMAINING(creation_space.small_below)+
- AREA_REMAINING(creation_space.small_above));
- if (max_heap_size == 0)
- return available_creation_space;
- else {
- long virtually_available =
- max_heap_size - S48_BYTES_TO_CELLS(s48_heap_live_size());
- if (virtually_available < available_creation_space)
- return virtually_available;
- else
- return available_creation_space;
- }
- }
- void s48_forbid_gcB() {
- gc_forbid_count++;
- }
- void s48_allow_gcB() {
- /*assert(gc_forbid_count > 0);*/
- gc_forbid_count--;
- }
- /* Small Objects */
- /* FPage 2 - 3 - 4 */
- void s48_make_availableAgc(long len_in_bytes) {
- #if (BIBOP_LOG)
- int i; /* for the generations-loop */
- int before_size[S48_GENERATIONS_COUNT];
- int after_size[S48_GENERATIONS_COUNT];
- #endif
- /* let's see if we run out of space in the current area... */
- if (AREA_REMAINING(creation_space.small) < len_in_bytes) {
- /* if we are under the water-mark, then continue above it... */
- if ((creation_space.small == creation_space.small_below) &&
- (len_in_bytes <= AREA_REMAINING(creation_space.small_above))) {
- /* FPage 2 */
- creation_space.small = creation_space.small_above;
- }
-
- /* While the image is still loading, and the creation_space is
- full, then the creation_space.small points to the small area
- created in current_space of the first generation. In this case
- the allocation is going on in this small area without memory
- limit. When the image has already been read, then a gc is
- allowed and the very next allocation of an object triggers the
- first collection.
- Just for the history: with a
- S48_CREATION_SPACE_SIZE of 512 KB (128 Pages as default), after
- the image is been loaded, there are 89.133 objects in the heap:
-
- - 14.177 objects in small_above area
- - 16.579 objects in the small_below area
- - 58.377 objects(!) in 19 areas in the current_space
- of the first generation.
- That is, only 1/3 comes into the creation_space and the rest
- 2/3 into the first generation, which causes a big delay by the
- first collection. I'll change this, by increasing the
- creation_space_size 3 times.
- From now on, the creation_space alone is responsible for the
- next collections: if we are above it already, and are allowed
- to collect some garbage, then do it. */
- else {
- if (gc_forbid_count == 0) {
- /* FPage 4 */
- #if (BIBOP_LOG)
- s48_bibop_log("CREATION SPACE WATER MARK");
- s48_bibop_log("creation_space.small_above: %i pages",
- S48_CREATION_SPACE_SIZE - current_water_mark);
- s48_bibop_log("creation_space.small_below: %i pages\n",
- current_water_mark);
- /*s48_bibop_log("NEW OBJECTS");
- s48_bibop_log("Bytes small_above = %i", get_creation_space_small_above());
- s48_bibop_log("Bytes small_below = %i", get_creation_space_small_below());*/
-
- if (s48_gc_count() == 0) {
- s48_bibop_log("Bytes small_gen = %i",
- calc_generation_size(&generations[0]));
- }
- s48_bibop_log("");
-
- /* save the current size before the collection */
- for (i = 0; i < S48_GENERATIONS_COUNT; i++) {
- before_size[i] = calc_generation_size(&generations[i]);
- }
- #endif
- s48_collect(FALSE);
- #if (BIBOP_LOG)
- /* save the current size after the collection */
- for (i = 0; i < S48_GENERATIONS_COUNT; i++) {
- after_size[i] = calc_generation_size(&generations[i]);
- }
-
- s48_bibop_log("AFTER COLLECTION");
- for (i = S48_GENERATIONS_COUNT - 1; i > -1; i--) {
- s48_bibop_log("gen: %i, last size %i, current size %i",
- i,
- before_size[i],
- after_size[i]);
- }
- s48_bibop_log("");
- #endif
- }
- /* if a gc is not allowed, or if after the collection, the
- creation-space is still too small, just use the first
- generation to allocate space, and allocate a new area if
- needed. */
- if ((gc_forbid_count != 0) ||
- (AREA_REMAINING(creation_space.small) < len_in_bytes)) {
- /* FPage 3 */
- creation_space.small = generations[0].current_space->small_area;
- if (AREA_REMAINING(creation_space.small) < len_in_bytes) {
- Area* new_area =
- s48_allocate_area(ulong_max(S48_MINIMUM_SMALL_AREA_SIZE,
- BYTES_TO_PAGES(len_in_bytes)),
- ulong_max(S48_MAXIMUM_SMALL_AREA_SIZE,
- BYTES_TO_PAGES(len_in_bytes)),
- 0,
- AREA_TYPE_SIZE_SMALL);
- new_area->next = generations[0].current_space->small_area;
- generations[0].current_space->small_area = new_area;
- creation_space.small = new_area;
- }
- }
- }
- }
- if (AREA_REMAINING(creation_space.small) < len_in_bytes)
- s48_gc_error("out of memory in s48_make_availableAgc(%d)", len_in_bytes);
- }
- s48_address s48_allocate_small(long len_in_bytes) {
- s48_address result;
- /* catch misuse of this function */
- /*assert(len_in_bytes <= S48_SMALL_OBJECT_LIMIT);*/
- result = creation_space.small->frontier;
- creation_space.small->frontier += S48_BYTES_TO_A_UNITS(len_in_bytes);
- assert(creation_space.small->frontier <= creation_space.small->end);
- return result;
- }
- /* Large Objects */
- static void s48_make_large_availableAgc(long len_in_bytes) {
- unsigned long current_size = 0;
- /* maybe keep tracking the size while allocating... */
- FOR_ALL_AREAS(creation_space.large,
- current_size += (area->frontier - area->start));
- if ((gc_forbid_count == 0) &&
- (current_size > S48_MAXIMUM_LARGE_CREATION_SPACE_SIZE)) {
- s48_collect(FALSE);
- }
- else {
- ;
- }
- }
- static s48_address s48_allocate_large(long len_in_bytes) {
- unsigned long len_in_pages = BYTES_TO_PAGES(len_in_bytes);
- Area *area;
- if (PAGES_TO_BYTES_LOSES_P(len_in_pages)) {
- /* pretend we're just out of memory */
- return NULL;
- };
- area = s48_allocate_area_without_crashing(len_in_pages,
- len_in_pages,
- 0,
- AREA_TYPE_SIZE_LARGE);
- if (area == NULL) {
- /* out of memory */
- return NULL;
- };
- area->frontier = area->start + len_in_bytes;
- area->next = creation_space.large;
- creation_space.large = area;
- return area->start;
- }
- /* "Mixed" Objects */
- inline static s48_address allocate_mixedAgc(long len_in_bytes) {
- if (len_in_bytes <= S48_SMALL_OBJECT_LIMIT) {
- s48_make_availableAgc(len_in_bytes);
- return s48_allocate_small(len_in_bytes);
- } else {
- s48_make_large_availableAgc(len_in_bytes);
- return s48_allocate_large(len_in_bytes);
- }
- }
- /*
- The Allocator (s48_allocate_tracedAgc)
- - If called from the portable Dumper: the len_in_bytes is of one
- object only. All objects are allocated one after the other.
- - If called from the TSC-Dumper: the len_in_bytes is of the whole
- image. At this phase a gc is forbidden. So if the creation_space is
- not big enough, we got a problem. So could increase the size of the
- creation_space to allocate the whole image, but we can't copy it
- blind, cause the static_space is divided in 3 areas: small, large and
- weaks obejcts. We have to find these 3 kinds of obejct separately !!!
- */
-
- s48_address s48_allocate_tracedAgc(long len_in_bytes) {
- return allocate_mixedAgc(len_in_bytes);
- }
- s48_address s48_allocate_untracedAgc(long len_in_bytes) {
- return allocate_mixedAgc(len_in_bytes);
- }
- /* Unmovable objects are allocated directly in a new large area, which
- are never moved in a collection. */
- psbool s48_gc_can_allocate_unmovableP() { return PSTRUE; }
- s48_address s48_allocate_traced_unmovableAgc(long len_in_bytes) {
- s48_make_large_availableAgc(len_in_bytes);
- return s48_allocate_large(len_in_bytes);
- }
- s48_address s48_allocate_untraced_unmovableAgc(long len_in_bytes) {
- s48_make_large_availableAgc(len_in_bytes);
- return s48_allocate_large(len_in_bytes);
- }
- psbool s48_unmovableP(s48_value stob) {
- Area* area = s48_memory_map_ref(S48_ADDRESS_AT_HEADER(stob));
- return ((area != NULL) &&
- (area->area_type_size == AREA_TYPE_SIZE_LARGE)) ? PSTRUE : PSFALSE;
- }
- /* Weak Pointers */
- s48_address s48_allocate_weakAgc(long len_in_bytes) {
- Area* area = creation_space.weaks;
- s48_address result;
- if (AREA_REMAINING(area) < len_in_bytes) {
- if (gc_forbid_count == 0) {
- s48_collect(FALSE);
- area = creation_space.weaks;
- }
- else {
- Area** areap = &generations[0].current_space->weaks_area;
- if (AREA_REMAINING(*areap) < len_in_bytes) {
- Area* new_area = s48_allocate_area(S48_MINIMUM_WEAK_AREA_SIZE,
- S48_MAXIMUM_WEAK_AREA_SIZE,
- 0, AREA_TYPE_SIZE_WEAKS);
- new_area->next = *areap;
- *areap = new_area;
- }
- area = *areap;
- }
- }
- if (AREA_REMAINING(area) < len_in_bytes)
- /* this should be impossible */
- s48_gc_error("out of memory in s48_allocate_weakAgc(%d).", len_in_bytes);
- result = area->frontier;
- area->frontier += S48_BYTES_TO_A_UNITS(len_in_bytes);
- return (result);
- }
- /*********************************************************************
- Walking down the heap
- *********************************************************************/
- inline static void walk_areas(void (*do_part)(s48_address, s48_address),
- Area* areas) {
- while (areas != NULL) {
- do_part(areas->start, areas->frontier);
- areas = areas->next;
- }
- }
- void s48_walk_heap(void (*do_part)(s48_address, s48_address)) {
- int i;
- walk_areas(do_part, creation_space.small_below);
- walk_areas(do_part, creation_space.small_above);
- walk_areas(do_part, creation_space.large);
- walk_areas(do_part, creation_space.weaks);
- for (i = 0; i < S48_GENERATIONS_COUNT; i++) {
- walk_areas(do_part, generations[i].current_space->small_area);
- walk_areas(do_part, generations[i].current_space->large_area);
- walk_areas(do_part, generations[i].current_space->weaks_area);
- }
- }
-
-
- /* Special area initialization for the BIBOP undumper in the last
- generation */
-
- /*****************************************************************************/
- void s48_initialize_image_areas(long small_bytes, long small_hp_d,
- long large_bytes, long large_hp_d,
- long weaks_bytes, long weaks_hp_d) {
- int image_generation = S48_GENERATIONS_COUNT - 1;
- s48_address start;
- s48_address small_end;
- s48_address large_end;
- s48_address end;
- long img_bytes;
- long i;
-
- /*Wrong image format ? */
- if ((small_bytes < 0) || (large_bytes < 0) || (weaks_bytes < 0)) return;
- /*Get a block */
- img_bytes = small_bytes + large_bytes + weaks_bytes;
-
- s48_allocate_image_area(img_bytes, &start, &end);
-
- if (img_bytes != (end - start)) {
- s48_gc_error("Image block is not OK!");
- }
-
- small_end = start + small_bytes;
- large_end = small_end + large_bytes;
-
-
- /* Set the start addresses */
- s48_set_new_small_start_addrB(start);
- s48_set_new_large_start_addrB(small_end);
- s48_set_new_weaks_start_addrB(large_end);
-
-
- /* Split this block and assign it to the last generation's areas */
- if (small_bytes > 0) {
- Area* small_img;
- small_img = s48_make_area(start, small_end,
- start + S48_BYTES_TO_A_UNITS(small_hp_d),
- image_generation, AREA_TYPE_SIZE_SMALL);
- small_img->action = GC_ACTION_IGNORE;
- generations[image_generation].current_space->small_area = small_img;
- }
- if (large_bytes > 0) {
- Area* large_img;
- large_img = s48_make_area(small_end, large_end,
- small_end + S48_BYTES_TO_A_UNITS(large_hp_d),
- image_generation, AREA_TYPE_SIZE_LARGE);
- large_img->action = GC_ACTION_IGNORE;
- generations[image_generation].current_space->large_area = large_img;
- }
- if (weaks_bytes > 0) {
- Area* weaks_img;
- weaks_img = s48_make_area(large_end, end,
- large_end + S48_BYTES_TO_A_UNITS(weaks_hp_d),
- image_generation, AREA_TYPE_SIZE_WEAKS);
- weaks_img->action = GC_ACTION_IGNORE;
- generations[image_generation].current_space->weaks_area = weaks_img;
- }
-
- return;
- }
-
- /*********************************************************************/
- long s48_get_new_small_size(void) {
- /*********************************************************************/
- s48_address start;
- s48_address end;
-
- start = generations[S48_GENERATIONS_COUNT - 1].current_space->small_area->start;
- end = generations[S48_GENERATIONS_COUNT - 1].current_space->small_area->end;
-
- return end - start;
- }
-
- /*********************************************************************/
- long s48_get_new_large_size(void) {
- /*********************************************************************/
- s48_address start;
- s48_address end;
-
- start = generations[S48_GENERATIONS_COUNT - 1].current_space->large_area->start;
- end = generations[S48_GENERATIONS_COUNT - 1].current_space->large_area->end;
-
- return end - start;
- }
-
- /*********************************************************************/
- long s48_get_new_weaks_size(void) {
- /*********************************************************************/
- s48_address start;
- s48_address end;
-
- start = generations[S48_GENERATIONS_COUNT - 1].current_space->weaks_area->start;
- end = generations[S48_GENERATIONS_COUNT - 1].current_space->weaks_area->end;
-
- return end - start;
- }
-
- /*********************************************************************/
- char * s48_get_new_small_end_addr(void) {
- /*********************************************************************/
- return generations[S48_GENERATIONS_COUNT - 1].current_space->small_area->end;
- }
-
- /*********************************************************************/
- char * s48_get_new_large_end_addr(void) {
- /*********************************************************************/
- return generations[S48_GENERATIONS_COUNT - 1].current_space->large_area->end;
- }
-
- /*********************************************************************/
- char * s48_get_new_weaks_end_addr(void) {
- /*********************************************************************/
- return generations[S48_GENERATIONS_COUNT - 1].current_space->weaks_area->end;
- }
- /*********************************************************************/
- void s48_check_heap_sizeB() {
- /*********************************************************************/
- unsigned long max_size = s48_max_heap_size(); /* cells */
- extern long s48_min_heap_size(void);
- unsigned long min_size = s48_min_heap_size(); /* cells */
-
- /* Check the given heap size (flag -h) and the actual one */
- if ((max_size != 0) && (min_size > max_size)) {
- s48_set_max_heap_sizeB( min_size );
- fprintf(stderr,
- "Maximum heap size %ld is too small, using %ld cells instead.\n", max_size,
- s48_max_heap_size());
- }
- }
|