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