6 relocation_type factor_vm::relocation_type_of(relocation_entry r)
8 return (relocation_type)((r & 0xf0000000) >> 28);
11 relocation_class factor_vm::relocation_class_of(relocation_entry r)
13 return (relocation_class)((r & 0x0f000000) >> 24);
16 cell factor_vm::relocation_offset_of(relocation_entry r)
18 return (r & 0x00ffffff);
21 void factor_vm::flush_icache_for(code_block *block)
23 flush_icache((cell)block,block->size());
26 int factor_vm::number_of_parameters(relocation_type type)
43 case RT_MEGAMORPHIC_CACHE_HITS:
48 critical_error("Bad rel type",type);
49 return -1; /* Can't happen */
53 void *factor_vm::object_xt(cell obj)
55 switch(tagged<object>(obj).type())
58 return untag<word>(obj)->xt;
60 return untag<quotation>(obj)->xt;
62 critical_error("Expected word or quotation",obj);
67 void *factor_vm::xt_pic(word *w, cell tagged_quot)
69 if(!to_boolean(tagged_quot) || max_pic_size == 0)
73 quotation *quot = untag<quotation>(tagged_quot);
81 void *factor_vm::word_xt_pic(word *w)
83 return xt_pic(w,w->pic_def);
86 void *factor_vm::word_xt_pic_tail(word *w)
88 return xt_pic(w,w->pic_tail_def);
91 /* References to undefined symbols are patched up to call this function on
93 void factor_vm::undefined_symbol()
95 general_error(ERROR_UNDEFINED_SYMBOL,false_object,false_object,NULL);
98 void undefined_symbol()
100 return tls_vm()->undefined_symbol();
103 /* Look up an external library symbol referenced by a compiled code block */
104 void *factor_vm::get_rel_symbol(array *literals, cell index)
106 cell symbol = array_nth(literals,index);
107 cell library = array_nth(literals,index + 1);
109 dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
111 if(d != NULL && !d->dll)
112 return (void *)factor::undefined_symbol;
114 switch(tagged<object>(symbol).type())
116 case BYTE_ARRAY_TYPE:
118 symbol_char *name = alien_offset(symbol);
119 void *sym = ffi_dlsym(d,name);
125 return (void *)factor::undefined_symbol;
131 array *names = untag<array>(symbol);
132 for(i = 0; i < array_capacity(names); i++)
134 symbol_char *name = alien_offset(array_nth(names,i));
135 void *sym = ffi_dlsym(d,name);
140 return (void *)factor::undefined_symbol;
143 critical_error("Bad symbol specifier",symbol);
144 return (void *)factor::undefined_symbol;
148 cell factor_vm::compute_relocation(relocation_entry rel, cell index, code_block *compiled)
150 array *literals = (to_boolean(compiled->literals)
151 ? untag<array>(compiled->literals) : NULL);
152 cell offset = relocation_offset_of(rel) + (cell)compiled->xt();
154 #define ARG array_nth(literals,index)
156 switch(relocation_type_of(rel))
159 return (cell)primitives[untag_fixnum(ARG)];
161 return (cell)get_rel_symbol(literals,index);
165 return (cell)object_xt(ARG);
167 return (cell)word_xt_pic(untag<word>(ARG));
169 return (cell)word_xt_pic_tail(untag<word>(ARG));
172 fixnum arg = untag_fixnum(ARG);
173 return (arg >= 0 ? offset + arg : (cell)(compiled + 1) - arg);
176 return (cell)(compiled + 1);
180 return untag_fixnum(ARG);
181 case RT_MEGAMORPHIC_CACHE_HITS:
182 return (cell)&megamorphic_cache_hits;
184 return (cell)this + untag_fixnum(ARG);
185 case RT_CARDS_OFFSET:
187 case RT_DECKS_OFFSET:
190 critical_error("Bad rel type",rel);
191 return 0; /* Can't happen */
197 template<typename Iterator> void factor_vm::iterate_relocations(code_block *compiled, Iterator &iter)
199 if(to_boolean(compiled->relocation))
201 byte_array *relocation = untag<byte_array>(compiled->relocation);
204 cell length = array_capacity(relocation) / sizeof(relocation_entry);
206 for(cell i = 0; i < length; i++)
208 relocation_entry rel = relocation->data<relocation_entry>()[i];
209 iter(rel,index,compiled);
210 index += number_of_parameters(relocation_type_of(rel));
215 /* Store a 32-bit value into a PowerPC LIS/ORI sequence */
216 void factor_vm::store_address_2_2(cell *ptr, cell value)
218 ptr[-1] = ((ptr[-1] & ~0xffff) | ((value >> 16) & 0xffff));
219 ptr[ 0] = ((ptr[ 0] & ~0xffff) | (value & 0xffff));
222 /* Store a value into a bitfield of a PowerPC instruction */
223 void factor_vm::store_address_masked(cell *ptr, fixnum value, cell mask, fixnum shift)
225 /* This is unaccurate but good enough */
226 fixnum test = (fixnum)mask >> 1;
227 if(value <= -test || value >= test)
228 critical_error("Value does not fit inside relocation",0);
230 *ptr = ((*ptr & ~mask) | ((value >> shift) & mask));
233 /* Perform a fixup on a code block */
234 void factor_vm::store_address_in_code_block(cell klass, cell offset, fixnum absolute_value)
236 fixnum relative_value = absolute_value - offset;
240 case RC_ABSOLUTE_CELL:
241 *(cell *)offset = absolute_value;
244 *(u32*)offset = absolute_value;
247 *(u32*)offset = relative_value - sizeof(u32);
249 case RC_ABSOLUTE_PPC_2_2:
250 store_address_2_2((cell *)offset,absolute_value);
252 case RC_ABSOLUTE_PPC_2:
253 store_address_masked((cell *)offset,absolute_value,rel_absolute_ppc_2_mask,0);
255 case RC_RELATIVE_PPC_2:
256 store_address_masked((cell *)offset,relative_value,rel_relative_ppc_2_mask,0);
258 case RC_RELATIVE_PPC_3:
259 store_address_masked((cell *)offset,relative_value,rel_relative_ppc_3_mask,0);
261 case RC_RELATIVE_ARM_3:
262 store_address_masked((cell *)offset,relative_value - sizeof(cell) * 2,
263 rel_relative_arm_3_mask,2);
265 case RC_INDIRECT_ARM:
266 store_address_masked((cell *)offset,relative_value - sizeof(cell),
267 rel_indirect_arm_mask,0);
269 case RC_INDIRECT_ARM_PC:
270 store_address_masked((cell *)offset,relative_value - sizeof(cell) * 2,
271 rel_indirect_arm_mask,0);
274 critical_error("Bad rel class",klass);
279 struct literal_references_updater {
282 explicit literal_references_updater(factor_vm *parent_) : parent(parent_) {}
284 void operator()(relocation_entry rel, cell index, code_block *compiled)
286 if(parent->relocation_type_of(rel) == RT_IMMEDIATE)
288 cell offset = parent->relocation_offset_of(rel) + (cell)(compiled + 1);
289 array *literals = parent->untag<array>(compiled->literals);
290 fixnum absolute_value = array_nth(literals,index);
291 parent->store_address_in_code_block(parent->relocation_class_of(rel),offset,absolute_value);
296 /* Update pointers to literals from compiled code. */
297 void factor_vm::update_literal_references(code_block *compiled)
299 if(!code->needs_fixup_p(compiled))
301 literal_references_updater updater(this);
302 iterate_relocations(compiled,updater);
303 flush_icache_for(compiled);
307 /* Compute an address to store at a relocation */
308 void factor_vm::relocate_code_block_step(relocation_entry rel, cell index, code_block *compiled)
311 if(to_boolean(compiled->literals))
312 tagged<array>(compiled->literals).untag_check(this);
313 if(to_boolean(compiled->relocation))
314 tagged<byte_array>(compiled->relocation).untag_check(this);
317 store_address_in_code_block(relocation_class_of(rel),
318 relocation_offset_of(rel) + (cell)compiled->xt(),
319 compute_relocation(rel,index,compiled));
322 struct word_references_updater {
325 explicit word_references_updater(factor_vm *parent_) : parent(parent_) {}
326 void operator()(relocation_entry rel, cell index, code_block *compiled)
328 relocation_type type = parent->relocation_type_of(rel);
329 if(type == RT_XT || type == RT_XT_PIC || type == RT_XT_PIC_TAIL)
330 parent->relocate_code_block_step(rel,index,compiled);
334 /* Relocate new code blocks completely; updating references to literals,
335 dlsyms, and words. For all other words in the code heap, we only need
336 to update references to other words, without worrying about literals
338 void factor_vm::update_word_references(code_block *compiled)
340 if(code->needs_fixup_p(compiled))
341 relocate_code_block(compiled);
342 /* update_word_references() is always applied to every block in
343 the code heap. Since it resets all call sites to point to
344 their canonical XT (cold entry point for non-tail calls,
345 standard entry point for tail calls), it means that no PICs
346 are referenced after this is done. So instead of polluting
347 the code heap with dead PICs that will be freed on the next
348 GC, we add them to the free list immediately. */
349 else if(compiled->type() == PIC_TYPE)
350 code->code_heap_free(compiled);
353 word_references_updater updater(this);
354 iterate_relocations(compiled,updater);
355 flush_icache_for(compiled);
359 /* This runs after a full collection */
360 struct literal_and_word_references_updater {
363 explicit literal_and_word_references_updater(factor_vm *parent_) : parent(parent_) {}
365 void operator()(relocation_entry rel, cell index, code_block *compiled)
367 relocation_type type = parent->relocation_type_of(rel);
374 parent->relocate_code_block_step(rel,index,compiled);
382 void factor_vm::update_code_block_for_full_gc(code_block *compiled)
384 if(code->needs_fixup_p(compiled))
385 relocate_code_block(compiled);
388 literal_and_word_references_updater updater(this);
389 iterate_relocations(compiled,updater);
390 flush_icache_for(compiled);
394 void factor_vm::check_code_address(cell address)
397 assert(address >= code->seg->start && address < code->seg->end);
401 struct code_block_relocator {
404 explicit code_block_relocator(factor_vm *parent_) : parent(parent_) {}
406 void operator()(relocation_entry rel, cell index, code_block *compiled)
408 parent->relocate_code_block_step(rel,index,compiled);
412 /* Perform all fixups on a code block */
413 void factor_vm::relocate_code_block(code_block *compiled)
415 code->needs_fixup.erase(compiled);
416 code_block_relocator relocator(this);
417 iterate_relocations(compiled,relocator);
418 flush_icache_for(compiled);
421 /* Fixup labels. This is done at compile time, not image load time */
422 void factor_vm::fixup_labels(array *labels, code_block *compiled)
425 cell size = array_capacity(labels);
427 for(i = 0; i < size; i += 3)
429 cell klass = untag_fixnum(array_nth(labels,i));
430 cell offset = untag_fixnum(array_nth(labels,i + 1));
431 cell target = untag_fixnum(array_nth(labels,i + 2));
433 store_address_in_code_block(klass,
434 offset + (cell)(compiled + 1),
435 target + (cell)(compiled + 1));
440 code_block *factor_vm::allot_code_block(cell size, cell type)
442 heap_block *block = code->heap_allot(size + sizeof(code_block),type);
444 /* If allocation failed, do a full GC and compact the code heap.
445 A full GC that occurs as a result of the data heap filling up does not
446 trigger a compaction. This setup ensures that most GCs do not compact
447 the code heap, but if the code fills up, it probably means it will be
448 fragmented after GC anyway, so its best to compact. */
451 primitive_compact_gc();
452 block = code->heap_allot(size + sizeof(code_block),type);
454 /* Insufficient room even after code GC, give up */
457 cell used, total_free, max_free;
458 code->heap_usage(&used,&total_free,&max_free);
460 print_string("Code heap stats:\n");
461 print_string("Used: "); print_cell(used); nl();
462 print_string("Total free space: "); print_cell(total_free); nl();
463 print_string("Largest free block: "); print_cell(max_free); nl();
464 fatal_error("Out of memory in add-compiled-block",0);
468 return (code_block *)block;
472 code_block *factor_vm::add_code_block(cell type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_)
474 gc_root<byte_array> code(code_,this);
475 gc_root<object> labels(labels_,this);
476 gc_root<object> owner(owner_,this);
477 gc_root<byte_array> relocation(relocation_,this);
478 gc_root<array> literals(literals_,this);
480 cell code_length = align8(array_capacity(code.untagged()));
481 code_block *compiled = allot_code_block(code_length,type);
483 compiled->owner = owner.value();
485 /* slight space optimization */
486 if(relocation.type() == BYTE_ARRAY_TYPE && array_capacity(relocation.untagged()) == 0)
487 compiled->relocation = false_object;
489 compiled->relocation = relocation.value();
491 if(literals.type() == ARRAY_TYPE && array_capacity(literals.untagged()) == 0)
492 compiled->literals = false_object;
494 compiled->literals = literals.value();
497 memcpy(compiled + 1,code.untagged() + 1,code_length);
500 if(to_boolean(labels.value()))
501 fixup_labels(labels.as<array>().untagged(),compiled);
503 /* next time we do a minor GC, we have to scan the code heap for
505 this->code->write_barrier(compiled);
506 this->code->needs_fixup.insert(compiled);