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