1 /*
2  * Part of Scheme 48 1.9.  See file COPYING for notices and license.
3  *
4  * Authors: David Frese, Robert Ransom
5  */
6 
7 #include <stdlib.h>
8 #include <string.h>
9 #include "utils.h"
10 #include "areas.h"
11 #include "page_constants.h"
12 #include "memory_map.h"
13 #include "area_roots.h"
14 #include "page_alloc.h"
15 #include "gc_config.h"
16 #include "remset.h"
17 
make_area(s48_address start,s48_address end,s48_address frontier,unsigned char generation_index,area_type_size_t area_type_size)18 static Area* make_area(s48_address start, s48_address end,
19 		       s48_address frontier,
20 		       unsigned char generation_index,
21 		       area_type_size_t area_type_size) {
22   Area* area = (Area*)malloc(sizeof(Area));
23   if (area == NULL) s48_gc_error("make_area: out of memory");
24   area->start = start;
25   area->end = end;
26   area->frontier = frontier;
27   area->trace = start;
28   area->next = NULL;
29   area->generation_index = generation_index;
30   area->area_type_size = area_type_size;
31   s48_init_dirty_vector(area);
32 #if S48_USE_REMEMBERED_SETS==TRUE
33   area->remset = s48_make_remset();
34 #endif
35   return area;
36 }
37 
free_area(Area * area)38 inline static void free_area(Area* area) {
39   s48_deinit_dirty_vector(area);
40 #if S48_USE_REMEMBERED_SETS==TRUE
41   s48_free_remset(area->remset);
42 #endif
43   free(area);
44 }
45 
46 /* delete_area deletes AREA from the linked list starting with START,
47    and returns the (eventually different) new start of the list. Does
48    NOT free the memory allocated for the area structure (nor the area
49    itself)! */
50 
s48_delete_area(Area * start,Area * area)51 Area* s48_delete_area(Area* start, Area* area) {
52   if (start == NULL)
53     /* no areas in the list? -> Done */
54     return start;
55   else if (start == area) {
56     /* list starts with AREA? -> next is new start */
57     Area* next = area->next;
58     area->next = NULL;
59     return next;
60   } else {
61     /* search for the area before AREA */
62     Area* prev = start;
63     /* if AREA is not in the list, prev->next can be NULL. But of
64        corse this should never happen !? */
65     while (prev->next != NULL) {
66       if (prev->next == area) {
67 	prev->next = area->next;
68 	break;
69       }
70       prev = prev->next;
71     }
72     area->next = NULL;
73     return start;
74   }
75 }
76 
77 /* Allocate an area of between MINIMUM and MAXIMUM pages, inclusive. */
78 
s48_allocate_area_without_crashing(unsigned long minimum,unsigned long maximum,unsigned char generation_index,area_type_size_t area_type_size)79 Area* s48_allocate_area_without_crashing(unsigned long minimum,
80 					 unsigned long maximum,
81 					 unsigned char generation_index,
82 					 area_type_size_t area_type_size) {
83   s48_address start;
84   Area* area;
85   unsigned long size = s48_allocate_pages(minimum, maximum, &start);
86 
87   if (size == 0) {
88     return NULL;
89   };
90 
91 #if (BIBOP_LOG)
92   s48_bibop_log("s48_allocate_pages: size = %i",
93 	    size);
94 #endif
95 
96   /* Safe because S48_ALLOCATE_PAGES has already checked MINIMUM and
97      MAXIMUM with PAGES_TO_BYTES_LOSES_P, and SIZE is less than
98      MAXIMUM.
99 
100      This call does crash if S48_MAKE_AREA cannot allocate an Area
101      struct, but avoiding an out-of-memory crash here is too hard to
102      be worthwhile. */
103   area = s48_make_area(start, ADD_PAGES_I_KNOW_THIS_CAN_OVERFLOW(start, size),
104 		       start,
105 		       generation_index, area_type_size);
106 
107   return area;
108 }
109 
s48_allocate_area(unsigned long minimum,unsigned long maximum,unsigned char generation_index,area_type_size_t area_type_size)110 Area* s48_allocate_area(unsigned long minimum, unsigned long maximum,
111 			unsigned char generation_index,
112 			area_type_size_t area_type_size) {
113   Area* area = s48_allocate_area_without_crashing(minimum, maximum,
114 						  generation_index,
115 						  area_type_size);
116 
117   if (area == NULL) {
118     s48_gc_error("s48_allocate_area: out of memory");
119   }
120 
121   return area;
122 }
123 
124 /* Free the pages covered by AREA, and free the struct itself too. */
125 
s48_free_area(Area * area)126 void s48_free_area(Area* area) {
127   unsigned long size = BYTES_TO_PAGES(area->end - area->start);
128   s48_address start = area->start;
129   unsigned long i;
130 
131   s48_free_pagesB(start, size);
132 
133   /* This is not really needed, I think. It's only a waste of time */
134   for (i = 0; i < size; i++) {
135     /* Safe because I is less than SIZE, which cannot cause an
136        overflow here. */
137     s48_memory_map_setB(ADD_PAGES_I_KNOW_THIS_CAN_OVERFLOW(start, i), NULL);
138   }
139 
140 #ifndef NDEBUG
141   /* Blank it out, to find errors more easily */
142   memset(area->start, 0, area->end - area->start);
143 #endif
144 
145   free_area(area);
146 }
147 
148 /* Call s48_free_area on all areas in the list starting with START */
s48_free_areas(Area * start)149 void s48_free_areas(Area* start) {
150   while (start != NULL) {
151     Area* next = start->next;
152     s48_free_area(start);
153     start = next;
154   }
155 }
156 
157 /* Get the type size of this stob's area: small, large, weaks. Called
158    from the BIBOP dumper */
s48_area_type_size(s48_value stob)159 area_type_size_t s48_area_type_size(s48_value stob) {
160   Area* area;
161   area = s48_memory_map_ref(S48_ADDRESS_AT_HEADER(stob));
162 
163   if (area == NULL) {
164     return AREA_TYPE_SIZE_ILLEGAL;
165   }
166 
167   return area->area_type_size;
168 }
169 
170 
171 /* Allocate a block for the whole image */
s48_allocate_image_area(long bytes,s48_address * start,s48_address * end)172 void s48_allocate_image_area(long bytes, s48_address* start, s48_address* end) {
173 
174   s48_address memory;
175 
176   memory = (s48_address)malloc(bytes + BYTES_PER_PAGE);
177 
178   if (memory == NULL) s48_gc_error("s48_allocate_image_area: out of memory\n");
179 
180   *start = PAGE_START_ADDRESS(memory + BYTES_PER_PAGE - 1);
181   *end = PAGE_START_ADDRESS(*start + bytes);
182 
183   return;
184 }
185 
186 /* Wrap the static make_area */
s48_make_area(s48_address start,s48_address end,s48_address frontier,unsigned char generation_index,area_type_size_t area_type_size)187 Area* s48_make_area(s48_address start, s48_address end,
188 		    s48_address frontier,
189 		    unsigned char generation_index,
190 		    area_type_size_t area_type_size) {
191   Area* area = make_area(start, end, frontier, generation_index, area_type_size);
192   /* The area is put into all memory-map cells that are covered by
193      it. */
194   int size = BYTES_TO_PAGES(end-start);
195   int i;
196   for (i = 0; i < size; i++)
197     /* Safe because I is less than SIZE, which cannot cause an
198        overflow here. */
199     s48_memory_map_setB(ADD_PAGES_I_KNOW_THIS_CAN_OVERFLOW(start, i), area);
200   return area;
201 }
202