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