Merge branch 'master' of git://factorcode.org/git/factor
[factor/jcg.git] / vm / code_heap.c
blob9a1c45c7df9e90c287f96ea56ba70c9757331b92
1 #include "master.h"
3 /* References to undefined symbols are patched up to call this function on
4 image load */
5 void undefined_symbol(void)
7 general_error(ERROR_UNDEFINED_SYMBOL,F,F,NULL);
10 INLINE CELL get_literal(CELL literals_start, CELL num)
12 return get(CREF(literals_start,num));
15 /* Look up an external library symbol referenced by a compiled code block */
16 void *get_rel_symbol(F_REL *rel, CELL literals_start)
18 CELL arg = REL_ARGUMENT(rel);
19 CELL symbol = get_literal(literals_start,arg);
20 CELL library = get_literal(literals_start,arg + 1);
22 F_DLL *dll = (library == F ? NULL : untag_dll(library));
24 if(dll != NULL && !dll->dll)
25 return undefined_symbol;
27 if(type_of(symbol) == BYTE_ARRAY_TYPE)
29 F_SYMBOL *name = alien_offset(symbol);
30 void *sym = ffi_dlsym(dll,name);
32 if(sym)
33 return sym;
35 else if(type_of(symbol) == ARRAY_TYPE)
37 CELL i;
38 F_ARRAY *names = untag_object(symbol);
39 for(i = 0; i < array_capacity(names); i++)
41 F_SYMBOL *name = alien_offset(array_nth(names,i));
42 void *sym = ffi_dlsym(dll,name);
44 if(sym)
45 return sym;
49 return undefined_symbol;
52 /* Compute an address to store at a relocation */
53 INLINE CELL compute_code_rel(F_REL *rel,
54 CELL code_start, CELL literals_start)
56 CELL obj;
58 switch(REL_TYPE(rel))
60 case RT_PRIMITIVE:
61 return (CELL)primitives[REL_ARGUMENT(rel)];
62 case RT_DLSYM:
63 return (CELL)get_rel_symbol(rel,literals_start);
64 case RT_IMMEDIATE:
65 return get(CREF(literals_start,REL_ARGUMENT(rel)));
66 case RT_XT:
67 obj = get(CREF(literals_start,REL_ARGUMENT(rel)));
68 if(type_of(obj) == WORD_TYPE)
69 return (CELL)untag_word(obj)->xt;
70 else
71 return (CELL)untag_quotation(obj)->xt;
72 case RT_HERE:
73 return rel->offset + code_start + (short)REL_ARGUMENT(rel);
74 case RT_LABEL:
75 return code_start + REL_ARGUMENT(rel);
76 case RT_STACK_CHAIN:
77 return (CELL)&stack_chain;
78 default:
79 critical_error("Bad rel type",rel->type);
80 return -1; /* Can't happen */
84 /* Store a 32-bit value into a PowerPC LIS/ORI sequence */
85 INLINE void reloc_set_2_2(CELL cell, CELL value)
87 put(cell - CELLS,((get(cell - CELLS) & ~0xffff) | ((value >> 16) & 0xffff)));
88 put(cell,((get(cell) & ~0xffff) | (value & 0xffff)));
91 /* Store a value into a bitfield of a PowerPC instruction */
92 INLINE void reloc_set_masked(CELL cell, F_FIXNUM value, CELL mask, F_FIXNUM shift)
94 /* This is unaccurate but good enough */
95 F_FIXNUM test = (F_FIXNUM)mask >> 1;
96 if(value <= -test || value >= test)
97 critical_error("Value does not fit inside relocation",0);
99 u32 original = *(u32*)cell;
100 original &= ~mask;
101 *(u32*)cell = (original | ((value >> shift) & mask));
104 /* Perform a fixup on a code block */
105 void apply_relocation(CELL class, CELL offset, F_FIXNUM absolute_value)
107 F_FIXNUM relative_value = absolute_value - offset;
109 switch(class)
111 case RC_ABSOLUTE_CELL:
112 put(offset,absolute_value);
113 break;
114 case RC_ABSOLUTE:
115 *(u32*)offset = absolute_value;
116 break;
117 case RC_RELATIVE:
118 *(u32*)offset = relative_value - sizeof(u32);
119 break;
120 case RC_ABSOLUTE_PPC_2_2:
121 reloc_set_2_2(offset,absolute_value);
122 break;
123 case RC_RELATIVE_PPC_2:
124 reloc_set_masked(offset,relative_value,REL_RELATIVE_PPC_2_MASK,0);
125 break;
126 case RC_RELATIVE_PPC_3:
127 reloc_set_masked(offset,relative_value,REL_RELATIVE_PPC_3_MASK,0);
128 break;
129 case RC_RELATIVE_ARM_3:
130 reloc_set_masked(offset,relative_value - CELLS * 2,
131 REL_RELATIVE_ARM_3_MASK,2);
132 break;
133 case RC_INDIRECT_ARM:
134 reloc_set_masked(offset,relative_value - CELLS,
135 REL_INDIRECT_ARM_MASK,0);
136 break;
137 case RC_INDIRECT_ARM_PC:
138 reloc_set_masked(offset,relative_value - CELLS * 2,
139 REL_INDIRECT_ARM_MASK,0);
140 break;
141 default:
142 critical_error("Bad rel class",class);
143 break;
147 /* Perform all fixups on a code block */
148 void relocate_code_block(F_COMPILED *compiled, CELL code_start, CELL literals_start)
150 compiled->last_scan = NURSERY;
152 if(compiled->relocation != F)
154 F_BYTE_ARRAY *relocation = untag_object(compiled->relocation);
156 F_REL *rel = (F_REL *)(relocation + 1);
157 F_REL *rel_end = (F_REL *)((char *)rel + byte_array_capacity(relocation));
159 while(rel < rel_end)
161 CELL offset = rel->offset + code_start;
163 F_FIXNUM absolute_value = compute_code_rel(
164 rel,code_start,literals_start);
166 apply_relocation(REL_CLASS(rel),offset,absolute_value);
168 rel++;
172 flush_icache(code_start,literals_start - code_start);
175 /* Fixup labels. This is done at compile time, not image load time */
176 void fixup_labels(F_ARRAY *labels, CELL code_format, CELL code_start)
178 CELL i;
179 CELL size = array_capacity(labels);
181 for(i = 0; i < size; i += 3)
183 CELL class = to_fixnum(array_nth(labels,i));
184 CELL offset = to_fixnum(array_nth(labels,i + 1));
185 CELL target = to_fixnum(array_nth(labels,i + 2));
187 apply_relocation(class,
188 offset + code_start,
189 target + code_start);
193 /* Write a sequence of integers to memory, with 'format' bytes per integer */
194 void deposit_integers(CELL here, F_ARRAY *array, CELL format)
196 CELL count = array_capacity(array);
197 CELL i;
199 for(i = 0; i < count; i++)
201 F_FIXNUM value = to_fixnum(array_nth(array,i));
202 if(format == 1)
203 bput(here + i,value);
204 else if(format == sizeof(unsigned int))
205 *(unsigned int *)(here + format * i) = value;
206 else if(format == CELLS)
207 put(CREF(here,i),value);
208 else
209 critical_error("Bad format in deposit_integers()",format);
213 /* Write a sequence of tagged pointers to memory */
214 void deposit_objects(CELL here, F_ARRAY *array)
216 memcpy((void*)here,array + 1,array_capacity(array) * CELLS);
219 bool stack_traces_p(void)
221 return to_boolean(userenv[STACK_TRACES_ENV]);
224 CELL compiled_code_format(void)
226 return untag_fixnum_fast(userenv[JIT_CODE_FORMAT]);
229 CELL allot_code_block(CELL size)
231 CELL start = heap_allot(&code_heap,size);
233 /* If allocation failed, do a code GC */
234 if(start == 0)
236 gc();
237 start = heap_allot(&code_heap,size);
239 /* Insufficient room even after code GC, give up */
240 if(start == 0)
242 CELL used, total_free, max_free;
243 heap_usage(&code_heap,&used,&total_free,&max_free);
245 print_string("Code heap stats:\n");
246 print_string("Used: "); print_cell(used); nl();
247 print_string("Total free space: "); print_cell(total_free); nl();
248 print_string("Largest free block: "); print_cell(max_free); nl();
249 fatal_error("Out of memory in add-compiled-block",0);
253 return start;
256 /* Might GC */
257 F_COMPILED *add_compiled_block(
258 CELL type,
259 F_ARRAY *code,
260 F_ARRAY *labels,
261 CELL relocation,
262 F_ARRAY *literals)
264 CELL code_format = compiled_code_format();
266 CELL code_length = align8(array_capacity(code) * code_format);
267 CELL literals_length = array_capacity(literals) * CELLS;
269 REGISTER_ROOT(relocation);
270 REGISTER_UNTAGGED(code);
271 REGISTER_UNTAGGED(labels);
272 REGISTER_UNTAGGED(literals);
274 CELL here = allot_code_block(sizeof(F_COMPILED) + code_length + literals_length);
276 UNREGISTER_UNTAGGED(literals);
277 UNREGISTER_UNTAGGED(labels);
278 UNREGISTER_UNTAGGED(code);
279 UNREGISTER_ROOT(relocation);
281 /* compiled header */
282 F_COMPILED *header = (void *)here;
283 header->type = type;
284 header->last_scan = NURSERY;
285 header->code_length = code_length;
286 header->literals_length = literals_length;
287 header->relocation = relocation;
289 here += sizeof(F_COMPILED);
291 CELL code_start = here;
293 /* code */
294 deposit_integers(here,code,code_format);
295 here += code_length;
297 /* literals */
298 deposit_objects(here,literals);
299 here += literals_length;
301 /* fixup labels */
302 if(labels)
303 fixup_labels(labels,code_format,code_start);
305 /* next time we do a minor GC, we have to scan the code heap for
306 literals */
307 last_code_heap_scan = NURSERY;
309 return header;
312 void set_word_code(F_WORD *word, F_COMPILED *compiled)
314 if(compiled->type != WORD_TYPE)
315 critical_error("bad param to set_word_xt",(CELL)compiled);
317 word->code = compiled;
318 word->compiledp = T;
321 /* Allocates memory */
322 void default_word_code(F_WORD *word, bool relocate)
324 REGISTER_UNTAGGED(word);
325 jit_compile(word->def,relocate);
326 UNREGISTER_UNTAGGED(word);
328 word->code = untag_quotation(word->def)->code;
329 word->compiledp = F;
332 void primitive_modify_code_heap(void)
334 bool rescan_code_heap = to_boolean(dpop());
335 F_ARRAY *alist = untag_array(dpop());
337 CELL count = untag_fixnum_fast(alist->capacity);
338 CELL i;
339 for(i = 0; i < count; i++)
341 F_ARRAY *pair = untag_array(array_nth(alist,i));
343 F_WORD *word = untag_word(array_nth(pair,0));
345 CELL data = array_nth(pair,1);
347 if(data == F)
349 REGISTER_UNTAGGED(alist);
350 REGISTER_UNTAGGED(word);
351 default_word_code(word,false);
352 UNREGISTER_UNTAGGED(word);
353 UNREGISTER_UNTAGGED(alist);
355 else
357 F_ARRAY *compiled_code = untag_array(data);
359 F_ARRAY *literals = untag_array(array_nth(compiled_code,0));
360 CELL relocation = array_nth(compiled_code,1);
361 F_ARRAY *labels = untag_array(array_nth(compiled_code,2));
362 F_ARRAY *code = untag_array(array_nth(compiled_code,3));
364 REGISTER_UNTAGGED(alist);
365 REGISTER_UNTAGGED(word);
367 F_COMPILED *compiled = add_compiled_block(
368 WORD_TYPE,
369 code,
370 labels,
371 relocation,
372 literals);
374 UNREGISTER_UNTAGGED(word);
375 UNREGISTER_UNTAGGED(alist);
377 set_word_code(word,compiled);
380 REGISTER_UNTAGGED(alist);
381 update_word_xt(word);
382 UNREGISTER_UNTAGGED(alist);
385 /* If there were any interned words in the set, we relocate all XT
386 references in the entire code heap. But if all the words are
387 uninterned, it is impossible that other words reference them, so we
388 only have to relocate the new words. This makes compile-call much
389 more efficient */
390 if(rescan_code_heap)
391 iterate_code_heap(relocate_code_block);
392 else
394 for(i = 0; i < count; i++)
396 F_ARRAY *pair = untag_array(array_nth(alist,i));
397 F_WORD *word = untag_word(array_nth(pair,0));
399 iterate_code_heap_step(word->code,relocate_code_block);