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