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