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 {
70 bool reset_inline_caches;
72 update_word_references_relocation_visitor(
74 bool reset_inline_caches_) :
76 reset_inline_caches(reset_inline_caches_) {}
78 void operator()(instruction_operand op)
84 code_block *compiled = op.load_code_block();
85 cell owner = compiled->owner;
87 op.store_value(parent->compute_entry_point_address(owner));
90 case RT_ENTRY_POINT_PIC:
92 code_block *compiled = op.load_code_block();
93 if(reset_inline_caches || !compiled->pic_p())
95 cell owner = parent->code_block_owner(compiled);
97 op.store_value(parent->compute_entry_point_pic_address(owner));
101 case RT_ENTRY_POINT_PIC_TAIL:
103 code_block *compiled = op.load_code_block();
104 if(reset_inline_caches || !compiled->pic_p())
106 cell owner = parent->code_block_owner(compiled);
107 if(to_boolean(owner))
108 op.store_value(parent->compute_entry_point_pic_tail_address(owner));
118 /* Relocate new code blocks completely; updating references to literals,
119 dlsyms, and words. For all other words in the code heap, we only need
120 to update references to other words, without worrying about literals
122 void factor_vm::update_word_references(code_block *compiled, bool reset_inline_caches)
124 if(code->uninitialized_p(compiled))
125 initialize_code_block(compiled);
126 /* update_word_references() is always applied to every block in
127 the code heap. Since it resets all call sites to point to
128 their canonical entry point (cold entry point for non-tail calls,
129 standard entry point for tail calls), it means that no PICs
130 are referenced after this is done. So instead of polluting
131 the code heap with dead PICs that will be freed on the next
132 GC, we add them to the free list immediately. */
133 else if(reset_inline_caches && compiled->pic_p())
134 code->free(compiled);
137 update_word_references_relocation_visitor visitor(this,reset_inline_caches);
138 compiled->each_instruction_operand(visitor);
139 compiled->flush_icache();
143 /* References to undefined symbols are patched up to call this function on
145 void factor_vm::undefined_symbol()
147 general_error(ERROR_UNDEFINED_SYMBOL,false_object,false_object);
150 void undefined_symbol()
152 return current_vm()->undefined_symbol();
155 /* Look up an external library symbol referenced by a compiled code block */
156 cell factor_vm::compute_dlsym_address(array *literals, cell index)
158 cell symbol = array_nth(literals,index);
159 cell library = array_nth(literals,index + 1);
161 dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
163 if(d != NULL && !d->handle)
164 return (cell)factor::undefined_symbol;
166 switch(tagged<object>(symbol).type())
168 case BYTE_ARRAY_TYPE:
170 symbol_char *name = alien_offset(symbol);
171 void *sym = ffi_dlsym(d,name);
176 return (cell)factor::undefined_symbol;
180 array *names = untag<array>(symbol);
181 for(cell i = 0; i < array_capacity(names); i++)
183 symbol_char *name = alien_offset(array_nth(names,i));
184 void *sym = ffi_dlsym(d,name);
189 return (cell)factor::undefined_symbol;
192 critical_error("Bad symbol specifier",symbol);
193 return (cell)factor::undefined_symbol;
197 cell factor_vm::compute_vm_address(cell arg)
199 return (cell)this + untag_fixnum(arg);
202 void factor_vm::store_external_address(instruction_operand op)
204 code_block *compiled = op.parent_code_block();
205 array *parameters = (to_boolean(compiled->parameters) ? untag<array>(compiled->parameters) : NULL);
206 cell index = op.parameter_index();
208 switch(op.rel_type())
211 op.store_value(compute_dlsym_address(parameters,index));
214 op.store_value((cell)compiled->entry_point());
216 case RT_MEGAMORPHIC_CACHE_HITS:
217 op.store_value((cell)&dispatch_stats.megamorphic_cache_hits);
220 op.store_value(compute_vm_address(array_nth(parameters,index)));
222 case RT_CARDS_OFFSET:
223 op.store_value(cards_offset);
225 case RT_DECKS_OFFSET:
226 op.store_value(decks_offset);
229 critical_error("Bad rel type",op.rel_type());
234 cell factor_vm::compute_here_address(cell arg, cell offset, code_block *compiled)
236 fixnum n = untag_fixnum(arg);
238 return (cell)compiled->entry_point() + offset + n;
240 return (cell)compiled->entry_point() - n;
243 struct initial_code_block_visitor {
248 explicit initial_code_block_visitor(factor_vm *parent_, cell literals_)
249 : parent(parent_), literals(literals_), literal_index(0) {}
253 return array_nth(untag<array>(literals),literal_index++);
256 void operator()(instruction_operand op)
258 switch(op.rel_type())
261 op.store_value(next_literal());
264 op.store_value(parent->compute_entry_point_address(next_literal()));
266 case RT_ENTRY_POINT_PIC:
267 op.store_value(parent->compute_entry_point_pic_address(next_literal()));
269 case RT_ENTRY_POINT_PIC_TAIL:
270 op.store_value(parent->compute_entry_point_pic_tail_address(next_literal()));
273 op.store_value(parent->compute_here_address(next_literal(),op.rel_offset(),op.parent_code_block()));
276 op.store_value(untag_fixnum(next_literal()));
279 parent->store_external_address(op);
285 /* Perform all fixups on a code block */
286 void factor_vm::initialize_code_block(code_block *compiled, cell literals)
288 initial_code_block_visitor visitor(this,literals);
289 compiled->each_instruction_operand(visitor);
290 compiled->flush_icache();
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 void factor_vm::initialize_code_block(code_block *compiled)
300 std::map<code_block *,cell>::iterator iter = code->uninitialized_blocks.find(compiled);
301 initialize_code_block(compiled,iter->second);
302 code->uninitialized_blocks.erase(iter);
305 /* Fixup labels. This is done at compile time, not image load time */
306 void factor_vm::fixup_labels(array *labels, code_block *compiled)
308 cell size = array_capacity(labels);
310 for(cell i = 0; i < size; i += 3)
312 relocation_class rel_class = (relocation_class)untag_fixnum(array_nth(labels,i));
313 cell offset = untag_fixnum(array_nth(labels,i + 1));
314 cell target = untag_fixnum(array_nth(labels,i + 2));
316 relocation_entry new_entry(RT_HERE,rel_class,offset);
318 instruction_operand op(new_entry,compiled,0);
319 op.store_value(target + (cell)compiled->entry_point());
324 code_block *factor_vm::allot_code_block(cell size, code_block_type type)
326 code_block *block = code->allocator->allot(size + sizeof(code_block));
328 /* If allocation failed, do a full GC and compact the code heap.
329 A full GC that occurs as a result of the data heap filling up does not
330 trigger a compaction. This setup ensures that most GCs do not compact
331 the code heap, but if the code fills up, it probably means it will be
332 fragmented after GC anyway, so its best to compact. */
335 primitive_compact_gc();
336 block = code->allocator->allot(size + sizeof(code_block));
338 /* Insufficient room even after code GC, give up */
341 std::cout << "Code heap used: " << code->allocator->occupied_space() << "\n";
342 std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
343 fatal_error("Out of memory in add-compiled-block",0);
347 block->set_type(type);
352 code_block *factor_vm::add_code_block(code_block_type type, cell code_, cell labels_, cell owner_, cell relocation_, cell parameters_, cell literals_)
354 data_root<byte_array> code(code_,this);
355 data_root<object> labels(labels_,this);
356 data_root<object> owner(owner_,this);
357 data_root<byte_array> relocation(relocation_,this);
358 data_root<array> parameters(parameters_,this);
359 data_root<array> literals(literals_,this);
361 cell code_length = array_capacity(code.untagged());
362 code_block *compiled = allot_code_block(code_length,type);
364 compiled->owner = owner.value();
366 /* slight space optimization */
367 if(relocation.type() == BYTE_ARRAY_TYPE && array_capacity(relocation.untagged()) == 0)
368 compiled->relocation = false_object;
370 compiled->relocation = relocation.value();
372 if(parameters.type() == ARRAY_TYPE && array_capacity(parameters.untagged()) == 0)
373 compiled->parameters = false_object;
375 compiled->parameters = parameters.value();
378 memcpy(compiled + 1,code.untagged() + 1,code_length);
381 if(to_boolean(labels.value()))
382 fixup_labels(labels.as<array>().untagged(),compiled);
384 /* Once we are ready, fill in literal and word references in this code
385 block's instruction operands. In most cases this is done right after this
386 method returns, except when compiling words with the non-optimizing
387 compiler at the beginning of bootstrap */
388 this->code->uninitialized_blocks.insert(std::make_pair(compiled,literals.value()));
390 /* next time we do a minor GC, we have to trace this code block, since
391 the fields of the code_block struct might point into nursery or aging */
392 this->code->write_barrier(compiled);