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