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