]> gitweb.factorcode.org Git - factor.git/blob - vm/image.cpp
removed a bunch of superflous blank lines
[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 void factorvm::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 factorvm::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(first_block(&code),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         build_free_list(&code,h->code_size);
73 }
74
75 /* Save the current image to disk */
76 bool factorvm::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 = heap_size(&code);
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(first_block(&code),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 factorvm::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(save_image)
132 {
133         PRIMITIVE_GETVM()->primitive_save_image();
134 }
135
136 inline void factorvm::primitive_save_image_and_exit()
137 {
138         /* We unbox this before doing anything else. This is the only point
139         where we might throw an error, so we have to throw an error here since
140         later steps destroy the current image. */
141         gc_root<byte_array> path(dpop(),this);
142         path.untag_check(this);
143
144         /* strip out userenv data which is set on startup anyway */
145         for(cell i = 0; i < USER_ENV; i++)
146         {
147                 if(!save_env_p(i)) userenv[i] = F;
148         }
149
150         /* do a full GC + code heap compaction */
151         performing_compaction = true;
152         compact_code_heap();
153         performing_compaction = false;
154
155         /* Save the image */
156         if(save_image((vm_char *)(path.untagged() + 1)))
157                 exit(0);
158         else
159                 exit(1);
160 }
161
162 PRIMITIVE(save_image_and_exit)
163 {       
164         PRIMITIVE_GETVM()->primitive_save_image_and_exit();
165 }
166
167 void factorvm::data_fixup(cell *cell)
168 {
169         if(immediate_p(*cell))
170                 return;
171
172         zone *tenured = &data->generations[data->tenured()];
173         *cell += (tenured->start - data_relocation_base);
174 }
175
176 void data_fixup(cell *cell, factorvm *myvm)
177 {
178         return myvm->data_fixup(cell);
179 }
180
181 template <typename TYPE> void factorvm::code_fixup(TYPE **handle)
182 {
183         TYPE *ptr = *handle;
184         TYPE *new_ptr = (TYPE *)(((cell)ptr) + (code.seg->start - code_relocation_base));
185         *handle = new_ptr;
186 }
187
188 void factorvm::fixup_word(word *word)
189 {
190         if(word->code)
191                 code_fixup(&word->code);
192         if(word->profiling)
193                 code_fixup(&word->profiling);
194         code_fixup(&word->xt);
195 }
196
197 void factorvm::fixup_quotation(quotation *quot)
198 {
199         if(quot->code)
200         {
201                 code_fixup(&quot->xt);
202                 code_fixup(&quot->code);
203         }
204         else
205                 quot->xt = (void *)lazy_jit_compile;
206 }
207
208 void factorvm::fixup_alien(alien *d)
209 {
210         d->expired = T;
211 }
212
213 void factorvm::fixup_stack_frame(stack_frame *frame)
214 {
215         code_fixup(&frame->xt);
216         code_fixup(&FRAME_RETURN_ADDRESS(frame));
217 }
218
219 void fixup_stack_frame(stack_frame *frame, factorvm *myvm)
220 {
221         return myvm->fixup_stack_frame(frame);
222 }
223
224 void factorvm::fixup_callstack_object(callstack *stack)
225 {
226         iterate_callstack_object(stack,factor::fixup_stack_frame);
227 }
228
229 /* Initialize an object in a newly-loaded image */
230 void factorvm::relocate_object(object *object)
231 {
232         cell hi_tag = object->h.hi_tag();
233         
234         /* Tuple relocation is a bit trickier; we have to fix up the
235         layout object before we can get the tuple size, so do_slots is
236         out of the question */
237         if(hi_tag == TUPLE_TYPE)
238         {
239                 tuple *t = (tuple *)object;
240                 data_fixup(&t->layout);
241
242                 cell *scan = t->data();
243                 cell *end = (cell *)((cell)object + untagged_object_size(object));
244
245                 for(; scan < end; scan++)
246                         data_fixup(scan);
247         }
248         else
249         {
250                 do_slots((cell)object,factor::data_fixup);
251
252                 switch(hi_tag)
253                 {
254                 case WORD_TYPE:
255                         fixup_word((word *)object);
256                         break;
257                 case QUOTATION_TYPE:
258                         fixup_quotation((quotation *)object);
259                         break;
260                 case DLL_TYPE:
261                         ffi_dlopen((dll *)object);
262                         break;
263                 case ALIEN_TYPE:
264                         fixup_alien((alien *)object);
265                         break;
266                 case CALLSTACK_TYPE:
267                         fixup_callstack_object((callstack *)object);
268                         break;
269                 }
270         }
271 }
272
273 /* Since the image might have been saved with a different base address than
274 where it is loaded, we need to fix up pointers in the image. */
275 void factorvm::relocate_data()
276 {
277         cell relocating;
278
279         cell i;
280         for(i = 0; i < USER_ENV; i++)
281                 data_fixup(&userenv[i]);
282
283         data_fixup(&T);
284         data_fixup(&bignum_zero);
285         data_fixup(&bignum_pos_one);
286         data_fixup(&bignum_neg_one);
287
288         zone *tenured = &data->generations[data->tenured()];
289
290         for(relocating = tenured->start;
291                 relocating < tenured->here;
292                 relocating += untagged_object_size((object *)relocating))
293         {
294                 object *obj = (object *)relocating;
295                 allot_barrier(obj);
296                 relocate_object(obj);
297         }
298 }
299
300 void factorvm::fixup_code_block(code_block *compiled)
301 {
302         /* relocate literal table data */
303         data_fixup(&compiled->relocation);
304         data_fixup(&compiled->literals);
305
306         relocate_code_block(compiled);
307 }
308
309 void fixup_code_block(code_block *compiled, factorvm *myvm)
310 {
311         return myvm->fixup_code_block(compiled);
312 }
313
314 void factorvm::relocate_code()
315 {
316         iterate_code_heap(factor::fixup_code_block);
317 }
318
319 /* Read an image file from disk, only done once during startup */
320 /* This function also initializes the data and code heaps */
321 void factorvm::load_image(vm_parameters *p)
322 {
323         FILE *file = OPEN_READ(p->image_path);
324         if(file == NULL)
325         {
326                 print_string("Cannot open image file: "); print_native_string(p->image_path); nl();
327                 print_string(strerror(errno)); nl();
328                 exit(1);
329         }
330
331         image_header h;
332         if(fread(&h,sizeof(image_header),1,file) != 1)
333                 fatal_error("Cannot read image header",0);
334
335         if(h.magic != image_magic)
336                 fatal_error("Bad image: magic number check failed",h.magic);
337
338         if(h.version != image_version)
339                 fatal_error("Bad image: version number check failed",h.version);
340         
341         load_data_heap(file,&h,p);
342         load_code_heap(file,&h,p);
343
344         fclose(file);
345
346         init_objects(&h);
347
348         relocate_data();
349         relocate_code();
350
351         /* Store image path name */
352         userenv[IMAGE_ENV] = allot_alien(F,(cell)p->image_path);
353 }
354
355 }