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 void factor_vm::check_code_address(cell address)
135 assert(address >= code->seg->start && address < code->seg->end);
139 /* References to undefined symbols are patched up to call this function on
141 void factor_vm::undefined_symbol()
143 general_error(ERROR_UNDEFINED_SYMBOL,false_object,false_object,NULL);
146 void undefined_symbol()
148 return tls_vm()->undefined_symbol();
151 /* Look up an external library symbol referenced by a compiled code block */
152 cell factor_vm::compute_dlsym_address(array *literals, cell index)
154 cell symbol = array_nth(literals,index);
155 cell library = array_nth(literals,index + 1);
157 dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
159 if(d != NULL && !d->handle)
160 return (cell)factor::undefined_symbol;
162 switch(tagged<object>(symbol).type())
164 case BYTE_ARRAY_TYPE:
166 symbol_char *name = alien_offset(symbol);
167 void *sym = ffi_dlsym(d,name);
172 return (cell)factor::undefined_symbol;
176 array *names = untag<array>(symbol);
177 for(cell i = 0; i < array_capacity(names); i++)
179 symbol_char *name = alien_offset(array_nth(names,i));
180 void *sym = ffi_dlsym(d,name);
185 return (cell)factor::undefined_symbol;
188 critical_error("Bad symbol specifier",symbol);
189 return (cell)factor::undefined_symbol;
193 cell factor_vm::compute_vm_address(cell arg)
195 return (cell)this + untag_fixnum(arg);
198 void factor_vm::store_external_address(instruction_operand op)
200 code_block *compiled = op.parent_code_block();
201 array *parameters = (to_boolean(compiled->parameters) ? untag<array>(compiled->parameters) : NULL);
202 cell index = op.parameter_index();
204 switch(op.rel_type())
207 op.store_value(compute_dlsym_address(parameters,index));
210 op.store_value((cell)compiled->entry_point());
212 case RT_MEGAMORPHIC_CACHE_HITS:
213 op.store_value((cell)&dispatch_stats.megamorphic_cache_hits);
216 op.store_value(compute_vm_address(array_nth(parameters,index)));
218 case RT_CARDS_OFFSET:
219 op.store_value(cards_offset);
221 case RT_DECKS_OFFSET:
222 op.store_value(decks_offset);
225 critical_error("Bad rel type",op.rel_type());
230 cell factor_vm::compute_here_address(cell arg, cell offset, code_block *compiled)
232 fixnum n = untag_fixnum(arg);
234 return (cell)compiled->entry_point() + offset + n;
236 return (cell)compiled->entry_point() - n;
239 struct initial_code_block_visitor {
244 explicit initial_code_block_visitor(factor_vm *parent_, cell literals_)
245 : parent(parent_), literals(literals_), literal_index(0) {}
249 return array_nth(untag<array>(literals),literal_index++);
252 void operator()(instruction_operand op)
254 switch(op.rel_type())
257 op.store_value(next_literal());
260 op.store_value(parent->compute_entry_point_address(next_literal()));
262 case RT_ENTRY_POINT_PIC:
263 op.store_value(parent->compute_entry_point_pic_address(next_literal()));
265 case RT_ENTRY_POINT_PIC_TAIL:
266 op.store_value(parent->compute_entry_point_pic_tail_address(next_literal()));
269 op.store_value(parent->compute_here_address(next_literal(),op.rel_offset(),op.parent_code_block()));
272 op.store_value(untag_fixnum(next_literal()));
275 parent->store_external_address(op);
281 /* Perform all fixups on a code block */
282 void factor_vm::initialize_code_block(code_block *compiled)
284 std::map<code_block *,cell>::iterator iter = code->uninitialized_blocks.find(compiled);
286 initial_code_block_visitor visitor(this,iter->second);
287 compiled->each_instruction_operand(visitor);
288 compiled->flush_icache();
290 code->uninitialized_blocks.erase(iter);
292 /* next time we do a minor GC, we have to trace this code block, since
293 the newly-installed instruction operands might point to literals in
295 code->write_barrier(compiled);
298 /* Fixup labels. This is done at compile time, not image load time */
299 void factor_vm::fixup_labels(array *labels, code_block *compiled)
301 cell size = array_capacity(labels);
303 for(cell i = 0; i < size; i += 3)
305 relocation_class rel_class = (relocation_class)untag_fixnum(array_nth(labels,i));
306 cell offset = untag_fixnum(array_nth(labels,i + 1));
307 cell target = untag_fixnum(array_nth(labels,i + 2));
309 relocation_entry new_entry(RT_HERE,rel_class,offset);
311 instruction_operand op(new_entry,compiled,0);
312 op.store_value(target + (cell)compiled->entry_point());
317 code_block *factor_vm::allot_code_block(cell size, code_block_type type)
319 code_block *block = code->allocator->allot(size + sizeof(code_block));
321 /* If allocation failed, do a full GC and compact the code heap.
322 A full GC that occurs as a result of the data heap filling up does not
323 trigger a compaction. This setup ensures that most GCs do not compact
324 the code heap, but if the code fills up, it probably means it will be
325 fragmented after GC anyway, so its best to compact. */
328 primitive_compact_gc();
329 block = code->allocator->allot(size + sizeof(code_block));
331 /* Insufficient room even after code GC, give up */
334 std::cout << "Code heap used: " << code->allocator->occupied_space() << "\n";
335 std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
336 fatal_error("Out of memory in add-compiled-block",0);
340 block->set_type(type);
345 code_block *factor_vm::add_code_block(code_block_type type, cell code_, cell labels_, cell owner_, cell relocation_, cell parameters_, cell literals_)
347 data_root<byte_array> code(code_,this);
348 data_root<object> labels(labels_,this);
349 data_root<object> owner(owner_,this);
350 data_root<byte_array> relocation(relocation_,this);
351 data_root<array> parameters(parameters_,this);
352 data_root<array> literals(literals_,this);
354 cell code_length = array_capacity(code.untagged());
355 code_block *compiled = allot_code_block(code_length,type);
357 compiled->owner = owner.value();
359 /* slight space optimization */
360 if(relocation.type() == BYTE_ARRAY_TYPE && array_capacity(relocation.untagged()) == 0)
361 compiled->relocation = false_object;
363 compiled->relocation = relocation.value();
365 if(parameters.type() == ARRAY_TYPE && array_capacity(parameters.untagged()) == 0)
366 compiled->parameters = false_object;
368 compiled->parameters = parameters.value();
371 memcpy(compiled + 1,code.untagged() + 1,code_length);
374 if(to_boolean(labels.value()))
375 fixup_labels(labels.as<array>().untagged(),compiled);
377 /* Once we are ready, fill in literal and word references in this code
378 block's instruction operands. In most cases this is done right after this
379 method returns, except when compiling words with the non-optimizing
380 compiler at the beginning of bootstrap */
381 this->code->uninitialized_blocks.insert(std::make_pair(compiled,literals.value()));
383 /* next time we do a minor GC, we have to trace this code block, since
384 the fields of the code_block struct might point into nursery or aging */
385 this->code->write_barrier(compiled);