6 cell code_block::owner_quot() const
8 tagged<object> executing(owner);
9 if (!optimized_p() && executing->type() == WORD_TYPE)
10 executing = executing.as<word>()->def;
11 return executing.value();
14 cell code_block::scan(factor_vm *vm, void *addr) const
18 case code_block_unoptimized:
20 tagged<object> obj(owner);
21 if(obj.type_p(WORD_TYPE))
22 obj = obj.as<word>()->def;
24 if(obj.type_p(QUOTATION_TYPE))
25 return tag_fixnum(vm->quot_code_offset_to_scan(obj.value(),offset(addr)));
29 case code_block_optimized:
33 critical_error("Bad frame type",type());
38 cell factor_vm::compute_entry_point_address(cell obj)
40 switch(tagged<object>(obj).type())
43 return (cell)untag<word>(obj)->entry_point;
45 return (cell)untag<quotation>(obj)->entry_point;
47 critical_error("Expected word or quotation",obj);
52 cell factor_vm::compute_entry_point_pic_address(word *w, cell tagged_quot)
54 if(!to_boolean(tagged_quot) || max_pic_size == 0)
55 return (cell)w->entry_point;
58 quotation *quot = untag<quotation>(tagged_quot);
59 if(quot_compiled_p(quot))
60 return (cell)quot->entry_point;
62 return (cell)w->entry_point;
66 cell factor_vm::compute_entry_point_pic_address(cell w_)
69 return compute_entry_point_pic_address(w.untagged(),w->pic_def);
72 cell factor_vm::compute_entry_point_pic_tail_address(cell w_)
75 return compute_entry_point_pic_address(w.untagged(),w->pic_tail_def);
78 cell factor_vm::code_block_owner(code_block *compiled)
80 tagged<object> owner(compiled->owner);
82 /* Cold generic word call sites point to quotations that call the
83 inline-cache-miss and inline-cache-miss-tail primitives. */
84 if(owner.type_p(QUOTATION_TYPE))
86 tagged<quotation> quot(owner.as<quotation>());
87 tagged<array> elements(quot->array);
89 FACTOR_ASSERT(array_capacity(elements.untagged()) == 5);
90 FACTOR_ASSERT(array_nth(elements.untagged(),4) == special_objects[PIC_MISS_WORD]
91 || array_nth(elements.untagged(),4) == special_objects[PIC_MISS_TAIL_WORD]);
93 tagged<wrapper> word_wrapper(array_nth(elements.untagged(),0));
94 return word_wrapper->object;
97 return compiled->owner;
100 struct update_word_references_relocation_visitor {
102 bool reset_inline_caches;
104 update_word_references_relocation_visitor(
106 bool reset_inline_caches_) :
108 reset_inline_caches(reset_inline_caches_) {}
110 void operator()(instruction_operand op)
112 switch(op.rel_type())
116 code_block *compiled = op.load_code_block();
117 cell owner = compiled->owner;
118 if(to_boolean(owner))
119 op.store_value(parent->compute_entry_point_address(owner));
122 case RT_ENTRY_POINT_PIC:
124 code_block *compiled = op.load_code_block();
125 if(reset_inline_caches || !compiled->pic_p())
127 cell owner = parent->code_block_owner(compiled);
128 if(to_boolean(owner))
129 op.store_value(parent->compute_entry_point_pic_address(owner));
133 case RT_ENTRY_POINT_PIC_TAIL:
135 code_block *compiled = op.load_code_block();
136 if(reset_inline_caches || !compiled->pic_p())
138 cell owner = parent->code_block_owner(compiled);
139 if(to_boolean(owner))
140 op.store_value(parent->compute_entry_point_pic_tail_address(owner));
150 /* Relocate new code blocks completely; updating references to literals,
151 dlsyms, and words. For all other words in the code heap, we only need
152 to update references to other words, without worrying about literals
154 void factor_vm::update_word_references(code_block *compiled, bool reset_inline_caches)
156 if(code->uninitialized_p(compiled))
157 initialize_code_block(compiled);
158 /* update_word_references() is always applied to every block in
159 the code heap. Since it resets all call sites to point to
160 their canonical entry point (cold entry point for non-tail calls,
161 standard entry point for tail calls), it means that no PICs
162 are referenced after this is done. So instead of polluting
163 the code heap with dead PICs that will be freed on the next
164 GC, we add them to the free list immediately. */
165 else if(reset_inline_caches && compiled->pic_p())
166 code->free(compiled);
169 update_word_references_relocation_visitor visitor(this,reset_inline_caches);
170 compiled->each_instruction_operand(visitor);
171 compiled->flush_icache();
175 /* Look up an external library symbol referenced by a compiled code block */
176 cell factor_vm::compute_dlsym_address(array *parameters, cell index)
178 cell symbol = array_nth(parameters,index);
179 cell library = array_nth(parameters,index + 1);
181 dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
183 void* undefined_symbol = (void*)factor::undefined_symbol;
184 undefined_symbol = FUNCTION_CODE_POINTER(undefined_symbol);
185 if(d != NULL && !d->handle)
186 return (cell)undefined_symbol;
188 switch(tagged<object>(symbol).type())
190 case BYTE_ARRAY_TYPE:
192 symbol_char *name = alien_offset(symbol);
193 void *sym = ffi_dlsym(d,name);
198 return (cell)undefined_symbol;
202 array *names = untag<array>(symbol);
203 for(cell i = 0; i < array_capacity(names); i++)
205 symbol_char *name = alien_offset(array_nth(names,i));
206 void *sym = ffi_dlsym(d,name);
211 return (cell)undefined_symbol;
214 critical_error("Bad symbol specifier",symbol);
215 return (cell)undefined_symbol;
220 cell factor_vm::compute_dlsym_toc_address(array *parameters, cell index)
222 cell symbol = array_nth(parameters,index);
223 cell library = array_nth(parameters,index + 1);
225 dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
227 void* undefined_toc = (void*)factor::undefined_symbol;
228 undefined_toc = FUNCTION_TOC_POINTER(undefined_toc);
229 if(d != NULL && !d->handle)
230 return (cell)undefined_toc;
232 switch(tagged<object>(symbol).type())
234 case BYTE_ARRAY_TYPE:
236 symbol_char *name = alien_offset(symbol);
237 void* toc = ffi_dlsym_toc(d,name);
241 return (cell)undefined_toc;
245 array *names = untag<array>(symbol);
246 for(cell i = 0; i < array_capacity(names); i++)
248 symbol_char *name = alien_offset(array_nth(names,i));
249 void *toc = ffi_dlsym_toc(d,name);
254 return (cell)undefined_toc;
257 critical_error("Bad symbol specifier",symbol);
258 return (cell)undefined_toc;
263 cell factor_vm::compute_vm_address(cell arg)
265 return (cell)this + untag_fixnum(arg);
268 void factor_vm::store_external_address(instruction_operand op)
270 code_block *compiled = op.compiled;
271 array *parameters = (to_boolean(compiled->parameters) ? untag<array>(compiled->parameters) : NULL);
272 cell index = op.index;
274 switch(op.rel_type())
277 op.store_value(compute_dlsym_address(parameters,index));
280 op.store_value((cell)compiled->entry_point());
282 case RT_MEGAMORPHIC_CACHE_HITS:
283 op.store_value((cell)&dispatch_stats.megamorphic_cache_hits);
286 op.store_value(compute_vm_address(array_nth(parameters,index)));
288 case RT_CARDS_OFFSET:
289 op.store_value(cards_offset);
291 case RT_DECKS_OFFSET:
292 op.store_value(decks_offset);
295 case RT_EXCEPTION_HANDLER:
296 op.store_value((cell)&factor::exception_handler);
301 op.store_value(compute_dlsym_toc_address(parameters,index));
304 case RT_INLINE_CACHE_MISS:
305 op.store_value((cell)&factor::inline_cache_miss);
308 op.store_value((cell)code->safepoint_page);
311 critical_error("Bad rel type in store_external_address()",op.rel_type());
316 cell factor_vm::compute_here_address(cell arg, cell offset, code_block *compiled)
318 fixnum n = untag_fixnum(arg);
320 return (cell)compiled->entry_point() + offset + n;
322 return (cell)compiled->entry_point() - n;
325 struct initial_code_block_visitor {
330 explicit initial_code_block_visitor(factor_vm *parent_, cell literals_)
331 : parent(parent_), literals(literals_), literal_index(0) {}
335 return array_nth(untag<array>(literals),literal_index++);
338 void operator()(instruction_operand op)
340 switch(op.rel_type())
343 op.store_value(next_literal());
346 op.store_value(parent->compute_entry_point_address(next_literal()));
348 case RT_ENTRY_POINT_PIC:
349 op.store_value(parent->compute_entry_point_pic_address(next_literal()));
351 case RT_ENTRY_POINT_PIC_TAIL:
352 op.store_value(parent->compute_entry_point_pic_tail_address(next_literal()));
355 op.store_value(parent->compute_here_address(next_literal(),op.rel_offset(),op.compiled));
358 op.store_value(untag_fixnum(next_literal()));
361 parent->store_external_address(op);
367 /* Perform all fixups on a code block */
368 void factor_vm::initialize_code_block(code_block *compiled, cell literals)
370 initial_code_block_visitor visitor(this,literals);
371 compiled->each_instruction_operand(visitor);
372 compiled->flush_icache();
374 /* next time we do a minor GC, we have to trace this code block, since
375 the newly-installed instruction operands might point to literals in
377 code->write_barrier(compiled);
380 void factor_vm::initialize_code_block(code_block *compiled)
382 std::map<code_block *,cell>::iterator iter = code->uninitialized_blocks.find(compiled);
383 initialize_code_block(compiled,iter->second);
384 code->uninitialized_blocks.erase(iter);
387 /* Fixup labels. This is done at compile time, not image load time */
388 void factor_vm::fixup_labels(array *labels, code_block *compiled)
390 cell size = array_capacity(labels);
392 for(cell i = 0; i < size; i += 3)
394 relocation_class rel_class = (relocation_class)untag_fixnum(array_nth(labels,i));
395 cell offset = untag_fixnum(array_nth(labels,i + 1));
396 cell target = untag_fixnum(array_nth(labels,i + 2));
398 relocation_entry new_entry(RT_HERE,rel_class,offset);
400 instruction_operand op(new_entry,compiled,0);
401 op.store_value(target + (cell)compiled->entry_point());
406 /* Allocates memory */
407 code_block *factor_vm::allot_code_block(cell size, code_block_type type)
409 code_block *block = code->allocator->allot(size + sizeof(code_block));
411 /* If allocation failed, do a full GC and compact the code heap.
412 A full GC that occurs as a result of the data heap filling up does not
413 trigger a compaction. This setup ensures that most GCs do not compact
414 the code heap, but if the code fills up, it probably means it will be
415 fragmented after GC anyway, so its best to compact. */
418 primitive_compact_gc();
419 block = code->allocator->allot(size + sizeof(code_block));
421 /* Insufficient room even after code GC, give up */
424 std::cout << "Code heap used: " << code->allocator->occupied_space() << "\n";
425 std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
426 fatal_error("Out of memory in add-compiled-block",0);
430 block->set_type(type);
435 /* Allocates memory */
436 code_block *factor_vm::add_code_block(code_block_type type, cell code_, cell labels_,
437 cell owner_, cell relocation_, cell parameters_, cell literals_,
438 cell frame_size_untagged)
440 data_root<byte_array> code(code_,this);
441 data_root<object> labels(labels_,this);
442 data_root<object> owner(owner_,this);
443 data_root<byte_array> relocation(relocation_,this);
444 data_root<array> parameters(parameters_,this);
445 data_root<array> literals(literals_,this);
447 cell code_length = array_capacity(code.untagged());
448 code_block *compiled = allot_code_block(code_length,type);
450 compiled->owner = owner.value();
452 /* slight space optimization */
453 if(relocation.type() == BYTE_ARRAY_TYPE && array_capacity(relocation.untagged()) == 0)
454 compiled->relocation = false_object;
456 compiled->relocation = relocation.value();
458 if(parameters.type() == ARRAY_TYPE && array_capacity(parameters.untagged()) == 0)
459 compiled->parameters = false_object;
461 compiled->parameters = parameters.value();
464 memcpy(compiled + 1,code.untagged() + 1,code_length);
467 if(to_boolean(labels.value()))
468 fixup_labels(labels.as<array>().untagged(),compiled);
470 compiled->set_stack_frame_size(frame_size_untagged);
472 /* Once we are ready, fill in literal and word references in this code
473 block's instruction operands. In most cases this is done right after this
474 method returns, except when compiling words with the non-optimizing
475 compiler at the beginning of bootstrap */
476 this->code->uninitialized_blocks.insert(std::make_pair(compiled,literals.value()));
477 this->code->all_blocks.insert((cell)compiled);
479 /* next time we do a minor GC, we have to trace this code block, since
480 the fields of the code_block struct might point into nursery or aging */
481 this->code->write_barrier(compiled);
486 /* Find the RT_DLSYM relocation nearest to the given return address. */
487 struct find_symbol_at_address_visitor {
493 find_symbol_at_address_visitor(factor_vm *parent_, cell return_address_) :
494 parent(parent_), return_address(return_address_),
495 symbol(false_object), library(false_object) { }
497 void operator()(instruction_operand op)
499 if(op.rel_type() == RT_DLSYM && op.pointer <= return_address)
501 code_block *compiled = op.compiled;
502 array *parameters = untag<array>(compiled->parameters);
503 cell index = op.index;
504 symbol = array_nth(parameters,index);
505 library = array_nth(parameters,index + 1);
510 /* References to undefined symbols are patched up to call this function on
511 image load. It finds the symbol and library, and throws an error. */
512 void factor_vm::undefined_symbol()
514 void *frame = ctx->callstack_top;
515 void *return_address = frame_return_address(frame);
516 code_block *compiled = code->code_block_for_address((cell)return_address);
517 find_symbol_at_address_visitor visitor(this, (cell)return_address);
518 compiled->each_instruction_operand(visitor);
519 if (!to_boolean(visitor.symbol))
520 critical_error("Can't find RT_DLSYM at return address", (cell)return_address);
522 general_error(ERROR_UNDEFINED_SYMBOL,visitor.symbol,visitor.library);
525 void undefined_symbol()
527 return current_vm()->undefined_symbol();