6 cell factor_vm::compute_entry_point_address(cell obj)
8 switch(tagged<object>(obj).type())
11 return (cell)untag<word>(obj)->entry_point;
13 return (cell)untag<quotation>(obj)->entry_point;
15 critical_error("Expected word or quotation",obj);
20 cell factor_vm::compute_entry_point_pic_address(word *w, cell tagged_quot)
22 if(!to_boolean(tagged_quot) || max_pic_size == 0)
23 return (cell)w->entry_point;
26 quotation *quot = untag<quotation>(tagged_quot);
27 if(quot_compiled_p(quot))
28 return (cell)quot->entry_point;
30 return (cell)w->entry_point;
34 cell factor_vm::compute_entry_point_pic_address(cell w_)
37 return compute_entry_point_pic_address(w.untagged(),w->pic_def);
40 cell factor_vm::compute_entry_point_pic_tail_address(cell w_)
43 return compute_entry_point_pic_address(w.untagged(),w->pic_tail_def);
46 cell factor_vm::code_block_owner(code_block *compiled)
48 tagged<object> owner(compiled->owner);
50 /* Cold generic word call sites point to quotations that call the
51 inline-cache-miss and inline-cache-miss-tail primitives. */
52 if(owner.type_p(QUOTATION_TYPE))
54 tagged<quotation> quot(owner.as<quotation>());
55 tagged<array> elements(quot->array);
57 assert(array_capacity(elements.untagged()) == 5);
58 assert(array_nth(elements.untagged(),4) == special_objects[PIC_MISS_WORD]
59 || array_nth(elements.untagged(),4) == special_objects[PIC_MISS_TAIL_WORD]);
61 tagged<wrapper> word_wrapper(array_nth(elements.untagged(),0));
62 return word_wrapper->object;
65 return compiled->owner;
68 struct update_word_references_relocation_visitor {
71 explicit update_word_references_relocation_visitor(factor_vm *parent_) : parent(parent_) {}
73 void operator()(instruction_operand op)
79 code_block *compiled = op.load_code_block();
80 cell owner = compiled->owner;
82 op.store_value(parent->compute_entry_point_address(owner));
85 case RT_ENTRY_POINT_PIC:
87 code_block *compiled = op.load_code_block();
88 cell owner = parent->code_block_owner(compiled);
90 op.store_value(parent->compute_entry_point_pic_address(owner));
93 case RT_ENTRY_POINT_PIC_TAIL:
95 code_block *compiled = op.load_code_block();
96 cell owner = parent->code_block_owner(compiled);
98 op.store_value(parent->compute_entry_point_pic_tail_address(owner));
107 /* Relocate new code blocks completely; updating references to literals,
108 dlsyms, and words. For all other words in the code heap, we only need
109 to update references to other words, without worrying about literals
111 void factor_vm::update_word_references(code_block *compiled)
113 if(code->uninitialized_p(compiled))
114 initialize_code_block(compiled);
115 /* update_word_references() is always applied to every block in
116 the code heap. Since it resets all call sites to point to
117 their canonical entry point (cold entry point for non-tail calls,
118 standard entry point for tail calls), it means that no PICs
119 are referenced after this is done. So instead of polluting
120 the code heap with dead PICs that will be freed on the next
121 GC, we add them to the free list immediately. */
122 else if(compiled->pic_p())
123 code->free(compiled);
126 update_word_references_relocation_visitor visitor(this);
127 compiled->each_instruction_operand(visitor);
128 compiled->flush_icache();
132 /* References to undefined symbols are patched up to call this function on
134 void factor_vm::undefined_symbol()
136 general_error(ERROR_UNDEFINED_SYMBOL,false_object,false_object,NULL);
139 void undefined_symbol()
141 return tls_vm()->undefined_symbol();
144 /* Look up an external library symbol referenced by a compiled code block */
145 cell factor_vm::compute_dlsym_address(array *literals, cell index)
147 cell symbol = array_nth(literals,index);
148 cell library = array_nth(literals,index + 1);
150 dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
152 if(d != NULL && !d->handle)
153 return (cell)factor::undefined_symbol;
155 switch(tagged<object>(symbol).type())
157 case BYTE_ARRAY_TYPE:
159 symbol_char *name = alien_offset(symbol);
160 void *sym = ffi_dlsym(d,name);
165 return (cell)factor::undefined_symbol;
169 array *names = untag<array>(symbol);
170 for(cell i = 0; i < array_capacity(names); i++)
172 symbol_char *name = alien_offset(array_nth(names,i));
173 void *sym = ffi_dlsym(d,name);
178 return (cell)factor::undefined_symbol;
181 critical_error("Bad symbol specifier",symbol);
182 return (cell)factor::undefined_symbol;
186 cell factor_vm::compute_vm_address(cell arg)
188 return (cell)this + untag_fixnum(arg);
191 void factor_vm::store_external_address(instruction_operand op)
193 code_block *compiled = op.parent_code_block();
194 array *parameters = (to_boolean(compiled->parameters) ? untag<array>(compiled->parameters) : NULL);
195 cell index = op.parameter_index();
197 switch(op.rel_type())
200 op.store_value(compute_dlsym_address(parameters,index));
203 op.store_value((cell)compiled->entry_point());
205 case RT_MEGAMORPHIC_CACHE_HITS:
206 op.store_value((cell)&dispatch_stats.megamorphic_cache_hits);
209 op.store_value(compute_vm_address(array_nth(parameters,index)));
211 case RT_CARDS_OFFSET:
212 op.store_value(cards_offset);
214 case RT_DECKS_OFFSET:
215 op.store_value(decks_offset);
218 critical_error("Bad rel type",op.rel_type());
223 cell factor_vm::compute_here_address(cell arg, cell offset, code_block *compiled)
225 fixnum n = untag_fixnum(arg);
227 return (cell)compiled->entry_point() + offset + n;
229 return (cell)compiled->entry_point() - n;
232 struct initial_code_block_visitor {
237 explicit initial_code_block_visitor(factor_vm *parent_, cell literals_)
238 : parent(parent_), literals(literals_), literal_index(0) {}
242 return array_nth(untag<array>(literals),literal_index++);
245 void operator()(instruction_operand op)
247 switch(op.rel_type())
250 op.store_value(next_literal());
253 op.store_value(parent->compute_entry_point_address(next_literal()));
255 case RT_ENTRY_POINT_PIC:
256 op.store_value(parent->compute_entry_point_pic_address(next_literal()));
258 case RT_ENTRY_POINT_PIC_TAIL:
259 op.store_value(parent->compute_entry_point_pic_tail_address(next_literal()));
262 op.store_value(parent->compute_here_address(next_literal(),op.rel_offset(),op.parent_code_block()));
265 op.store_value(untag_fixnum(next_literal()));
268 parent->store_external_address(op);
274 /* Perform all fixups on a code block */
275 void factor_vm::initialize_code_block(code_block *compiled)
277 std::map<code_block *,cell>::iterator iter = code->uninitialized_blocks.find(compiled);
279 initial_code_block_visitor visitor(this,iter->second);
280 compiled->each_instruction_operand(visitor);
281 compiled->flush_icache();
283 code->uninitialized_blocks.erase(iter);
285 /* next time we do a minor GC, we have to trace this code block, since
286 the newly-installed instruction operands might point to literals in
288 code->write_barrier(compiled);
291 /* Fixup labels. This is done at compile time, not image load time */
292 void factor_vm::fixup_labels(array *labels, code_block *compiled)
294 cell size = array_capacity(labels);
296 for(cell i = 0; i < size; i += 3)
298 relocation_class rel_class = (relocation_class)untag_fixnum(array_nth(labels,i));
299 cell offset = untag_fixnum(array_nth(labels,i + 1));
300 cell target = untag_fixnum(array_nth(labels,i + 2));
302 relocation_entry new_entry(RT_HERE,rel_class,offset);
304 instruction_operand op(new_entry,compiled,0);
305 op.store_value(target + (cell)compiled->entry_point());
310 code_block *factor_vm::allot_code_block(cell size, code_block_type type)
312 code_block *block = code->allocator->allot(size + sizeof(code_block));
314 /* If allocation failed, do a full GC and compact the code heap.
315 A full GC that occurs as a result of the data heap filling up does not
316 trigger a compaction. This setup ensures that most GCs do not compact
317 the code heap, but if the code fills up, it probably means it will be
318 fragmented after GC anyway, so its best to compact. */
321 primitive_compact_gc();
322 block = code->allocator->allot(size + sizeof(code_block));
324 /* Insufficient room even after code GC, give up */
327 std::cout << "Code heap used: " << code->allocator->occupied_space() << "\n";
328 std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
329 fatal_error("Out of memory in add-compiled-block",0);
333 block->set_type(type);
338 code_block *factor_vm::add_code_block(code_block_type type, cell code_, cell labels_, cell owner_, cell relocation_, cell parameters_, cell literals_)
340 data_root<byte_array> code(code_,this);
341 data_root<object> labels(labels_,this);
342 data_root<object> owner(owner_,this);
343 data_root<byte_array> relocation(relocation_,this);
344 data_root<array> parameters(parameters_,this);
345 data_root<array> literals(literals_,this);
347 cell code_length = array_capacity(code.untagged());
348 code_block *compiled = allot_code_block(code_length,type);
350 compiled->owner = owner.value();
352 /* slight space optimization */
353 if(relocation.type() == BYTE_ARRAY_TYPE && array_capacity(relocation.untagged()) == 0)
354 compiled->relocation = false_object;
356 compiled->relocation = relocation.value();
358 if(parameters.type() == ARRAY_TYPE && array_capacity(parameters.untagged()) == 0)
359 compiled->parameters = false_object;
361 compiled->parameters = parameters.value();
364 memcpy(compiled + 1,code.untagged() + 1,code_length);
367 if(to_boolean(labels.value()))
368 fixup_labels(labels.as<array>().untagged(),compiled);
370 /* Once we are ready, fill in literal and word references in this code
371 block's instruction operands. In most cases this is done right after this
372 method returns, except when compiling words with the non-optimizing
373 compiler at the beginning of bootstrap */
374 this->code->uninitialized_blocks.insert(std::make_pair(compiled,literals.value()));
376 /* next time we do a minor GC, we have to trace this code block, since
377 the fields of the code_block struct might point into nursery or aging */
378 this->code->write_barrier(compiled);