]> gitweb.factorcode.org Git - factor.git/blob - vmpp/image.cpp
83a48c8f249a8925ab0dc00462eecb589a24ffbf
[factor.git] / vmpp / image.cpp
1 #include "master.hpp"
2
3 /* Certain special objects in the image are known to the runtime */
4 static void init_objects(F_HEADER *h)
5 {
6         memcpy(userenv,h->userenv,sizeof(userenv));
7
8         T = h->t;
9         bignum_zero = h->bignum_zero;
10         bignum_pos_one = h->bignum_pos_one;
11         bignum_neg_one = h->bignum_neg_one;
12 }
13
14 CELL data_relocation_base;
15
16 static void load_data_heap(FILE *file, F_HEADER *h, F_PARAMETERS *p)
17 {
18         CELL good_size = h->data_size + (1 << 20);
19
20         if(good_size > p->tenured_size)
21                 p->tenured_size = good_size;
22
23         init_data_heap(p->gen_count,
24                 p->young_size,
25                 p->aging_size,
26                 p->tenured_size,
27                 p->secure_gc);
28
29         clear_gc_stats();
30
31         F_ZONE *tenured = &data_heap->generations[TENURED];
32
33         F_FIXNUM bytes_read = fread((void*)tenured->start,1,h->data_size,file);
34
35         if((CELL)bytes_read != h->data_size)
36         {
37                 print_string("truncated image: ");
38                 print_fixnum(bytes_read);
39                 print_string(" bytes read, ");
40                 print_cell(h->data_size);
41                 print_string(" bytes expected\n");
42                 fatal_error("load_data_heap failed",0);
43         }
44
45         tenured->here = tenured->start + h->data_size;
46         data_relocation_base = h->data_relocation_base;
47 }
48
49 CELL code_relocation_base;
50
51 static void load_code_heap(FILE *file, F_HEADER *h, F_PARAMETERS *p)
52 {
53         CELL good_size = h->code_size + (1 << 19);
54
55         if(good_size > p->code_size)
56                 p->code_size = good_size;
57
58         init_code_heap(p->code_size);
59
60         if(h->code_size != 0)
61         {
62                 size_t bytes_read = fread(first_block(&code_heap),1,h->code_size,file);
63                 if(bytes_read != h->code_size)
64                 {
65                         print_string("truncated image: ");
66                         print_fixnum(bytes_read);
67                         print_string(" bytes read, ");
68                         print_cell(h->code_size);
69                         print_string(" bytes expected\n");
70                         fatal_error("load_code_heap failed",0);
71                 }
72         }
73
74         code_relocation_base = h->code_relocation_base;
75         build_free_list(&code_heap,h->code_size);
76 }
77
78 /* Save the current image to disk */
79 bool save_image(const F_CHAR *filename)
80 {
81         FILE* file;
82         F_HEADER h;
83
84         file = OPEN_WRITE(filename);
85         if(file == NULL)
86         {
87                 print_string("Cannot open image file: "); print_native_string(filename); nl();
88                 print_string(strerror(errno)); nl();
89                 return false;
90         }
91
92         F_ZONE *tenured = &data_heap->generations[TENURED];
93
94         h.magic = IMAGE_MAGIC;
95         h.version = IMAGE_VERSION;
96         h.data_relocation_base = tenured->start;
97         h.data_size = tenured->here - tenured->start;
98         h.code_relocation_base = code_heap.segment->start;
99         h.code_size = heap_size(&code_heap);
100
101         h.t = T;
102         h.bignum_zero = bignum_zero;
103         h.bignum_pos_one = bignum_pos_one;
104         h.bignum_neg_one = bignum_neg_one;
105
106         CELL i;
107         for(i = 0; i < USER_ENV; i++)
108         {
109                 if(i < FIRST_SAVE_ENV)
110                         h.userenv[i] = F;
111                 else
112                         h.userenv[i] = userenv[i];
113         }
114
115         bool ok = true;
116
117         if(fwrite(&h,sizeof(F_HEADER),1,file) != 1) ok = false;
118         if(fwrite((void*)tenured->start,h.data_size,1,file) != 1) ok = false;
119         if(fwrite(first_block(&code_heap),h.code_size,1,file) != 1) ok = false;
120         if(fclose(file)) ok = false;
121
122         if(!ok)
123         {
124                 print_string("save-image failed: "); print_string(strerror(errno)); nl();
125         }
126
127         return ok;
128 }
129
130 void primitive_save_image(void)
131 {
132         /* do a full GC to push everything into tenured space */
133         gc();
134
135         save_image(unbox_native_string());
136 }
137
138 void primitive_save_image_and_exit(void)
139 {
140         /* We unbox this before doing anything else. This is the only point
141         where we might throw an error, so we have to throw an error here since
142         later steps destroy the current image. */
143         F_CHAR *path = unbox_native_string();
144
145         REGISTER_C_STRING(path);
146
147         /* strip out userenv data which is set on startup anyway */
148         CELL i;
149         for(i = 0; i < FIRST_SAVE_ENV; i++)
150                 userenv[i] = F;
151
152         for(i = LAST_SAVE_ENV + 1; i < STACK_TRACES_ENV; i++)
153                 userenv[i] = F;
154
155         /* do a full GC + code heap compaction */
156         performing_compaction = true;
157         compact_code_heap();
158         performing_compaction = false;
159
160         UNREGISTER_C_STRING(F_CHAR,path);
161
162         /* Save the image */
163         if(save_image(path))
164                 exit(0);
165         else
166                 exit(1);
167 }
168
169 static void data_fixup(CELL *cell)
170 {
171         if(immediate_p(*cell))
172                 return;
173
174         F_ZONE *tenured = &data_heap->generations[TENURED];
175         *cell += (tenured->start - data_relocation_base);
176 }
177
178 static void code_fixup(CELL cell)
179 {
180         CELL value = get(cell);
181         put(cell,value + (code_heap.segment->start - code_relocation_base));
182 }
183
184 static void fixup_word(F_WORD *word)
185 {
186         if(word->code)
187                 code_fixup((CELL)&word->code);
188         if(word->profiling)
189                 code_fixup((CELL)&word->profiling);
190         code_fixup((CELL)&word->xt);
191 }
192
193 static void fixup_quotation(F_QUOTATION *quot)
194 {
195         if(quot->compiledp == F)
196                 quot->xt = (void *)lazy_jit_compile;
197         else
198         {
199                 code_fixup((CELL)&quot->xt);
200                 code_fixup((CELL)&quot->code);
201         }
202 }
203
204 static void fixup_alien(F_ALIEN *d)
205 {
206         d->expired = T;
207 }
208
209 static void fixup_stack_frame(F_STACK_FRAME *frame)
210 {
211         code_fixup((CELL)&frame->xt);
212         code_fixup((CELL)&FRAME_RETURN_ADDRESS(frame));
213 }
214
215 static void fixup_callstack_object(F_CALLSTACK *stack)
216 {
217         iterate_callstack_object(stack,fixup_stack_frame);
218 }
219
220 /* Initialize an object in a newly-loaded image */
221 static void relocate_object(CELL relocating)
222 {
223         /* Tuple relocation is a bit trickier; we have to fix up the
224         fixup object before we can get the tuple size, so do_slots is
225         out of the question */
226         if(untag_header(get(relocating)) == TUPLE_TYPE)
227         {
228                 data_fixup((CELL *)relocating + 1);
229
230                 CELL scan = relocating + 2 * CELLS;
231                 CELL size = untagged_object_size(relocating);
232                 CELL end = relocating + size;
233
234                 while(scan < end)
235                 {
236                         data_fixup((CELL *)scan);
237                         scan += CELLS;
238                 }
239         }
240         else
241         {
242                 do_slots(relocating,data_fixup);
243
244                 switch(untag_header(get(relocating)))
245                 {
246                 case WORD_TYPE:
247                         fixup_word((F_WORD *)relocating);
248                         break;
249                 case QUOTATION_TYPE:
250                         fixup_quotation((F_QUOTATION *)relocating);
251                         break;
252                 case DLL_TYPE:
253                         ffi_dlopen((F_DLL *)relocating);
254                         break;
255                 case ALIEN_TYPE:
256                         fixup_alien((F_ALIEN *)relocating);
257                         break;
258                 case CALLSTACK_TYPE:
259                         fixup_callstack_object((F_CALLSTACK *)relocating);
260                         break;
261                 }
262         }
263 }
264
265 /* Since the image might have been saved with a different base address than
266 where it is loaded, we need to fix up pointers in the image. */
267 void relocate_data()
268 {
269         CELL relocating;
270
271         CELL i;
272         for(i = 0; i < USER_ENV; i++)
273                 data_fixup(&userenv[i]);
274
275         data_fixup(&T);
276         data_fixup(&bignum_zero);
277         data_fixup(&bignum_pos_one);
278         data_fixup(&bignum_neg_one);
279
280         F_ZONE *tenured = &data_heap->generations[TENURED];
281
282         for(relocating = tenured->start;
283                 relocating < tenured->here;
284                 relocating += untagged_object_size(relocating))
285         {
286                 allot_barrier(relocating);
287                 relocate_object(relocating);
288         }
289 }
290
291 static void fixup_code_block(F_CODE_BLOCK *compiled)
292 {
293         /* relocate literal table data */
294         data_fixup(&compiled->relocation);
295         data_fixup(&compiled->literals);
296
297         relocate_code_block(compiled);
298 }
299
300 void relocate_code()
301 {
302         iterate_code_heap(fixup_code_block);
303 }
304
305 /* Read an image file from disk, only done once during startup */
306 /* This function also initializes the data and code heaps */
307 void load_image(F_PARAMETERS *p)
308 {
309         FILE *file = OPEN_READ(p->image_path);
310         if(file == NULL)
311         {
312                 print_string("Cannot open image file: "); print_native_string(p->image_path); nl();
313                 print_string(strerror(errno)); nl();
314                 exit(1);
315         }
316
317         F_HEADER h;
318         if(fread(&h,sizeof(F_HEADER),1,file) != 1)
319                 fatal_error("Cannot read image header",0);
320
321         if(h.magic != IMAGE_MAGIC)
322                 fatal_error("Bad image: magic number check failed",h.magic);
323
324         if(h.version != IMAGE_VERSION)
325                 fatal_error("Bad image: version number check failed",h.version);
326         
327         load_data_heap(file,&h,p);
328         load_code_heap(file,&h,p);
329
330         fclose(file);
331
332         init_objects(&h);
333
334         relocate_data();
335         relocate_code();
336
337         /* Store image path name */
338         userenv[IMAGE_ENV] = tag_object(from_native_string(p->image_path));
339 }