5 cell code_block::owner_quot() const {
6 tagged<object> executing(owner);
7 if (!optimized_p() && executing->type() == WORD_TYPE)
8 executing = executing.as<word>()->def;
9 return executing.value();
12 /* If the code block is an unoptimized quotation, we can calculate the
13 scan offset. In all other cases -1 is returned. */
14 cell code_block::scan(factor_vm* vm, cell addr) const {
15 if (type() != code_block_unoptimized) {
16 return tag_fixnum(-1);
19 tagged<object> obj(owner);
20 if (obj.type_p(WORD_TYPE))
21 obj = obj.as<word>()->def;
22 if (!obj.type_p(QUOTATION_TYPE))
23 return tag_fixnum(-1);
25 cell ofs = offset(addr);
26 return tag_fixnum(vm->quot_code_offset_to_scan(obj.value(), ofs));
29 cell factor_vm::compute_entry_point_address(cell obj) {
30 switch (tagged<object>(obj).type()) {
32 return untag<word>(obj)->entry_point;
34 return untag<quotation>(obj)->entry_point;
36 critical_error("Expected word or quotation", obj);
41 cell factor_vm::compute_entry_point_pic_address(word* w, cell tagged_quot) {
42 if (!to_boolean(tagged_quot) || max_pic_size == 0)
43 return w->entry_point;
44 quotation* q = untag<quotation>(tagged_quot);
45 if (quotation_compiled_p(q))
46 return q->entry_point;
47 return w->entry_point;
50 cell factor_vm::compute_entry_point_pic_address(cell w_) {
52 return compute_entry_point_pic_address(w.untagged(), w->pic_def);
55 cell factor_vm::compute_entry_point_pic_tail_address(cell w_) {
57 return compute_entry_point_pic_address(w.untagged(), w->pic_tail_def);
60 cell factor_vm::code_block_owner(code_block* compiled) {
61 tagged<object> owner(compiled->owner);
63 /* Cold generic word call sites point to quotations that call the
64 inline-cache-miss and inline-cache-miss-tail primitives. */
65 if (owner.type_p(QUOTATION_TYPE)) {
66 tagged<quotation> quot(owner.as<quotation>());
67 tagged<array> elements(quot->array);
69 FACTOR_ASSERT(array_capacity(elements.untagged()) == 5);
70 FACTOR_ASSERT(array_nth(elements.untagged(), 4) ==
71 special_objects[PIC_MISS_WORD] ||
72 array_nth(elements.untagged(), 4) ==
73 special_objects[PIC_MISS_TAIL_WORD]);
75 tagged<wrapper> word_wrapper(array_nth(elements.untagged(), 0));
76 return word_wrapper->object;
78 return compiled->owner;
81 struct update_word_references_relocation_visitor {
83 bool reset_inline_caches;
85 update_word_references_relocation_visitor(factor_vm* parent,
86 bool reset_inline_caches)
87 : parent(parent), reset_inline_caches(reset_inline_caches) {}
89 void operator()(instruction_operand op) {
90 code_block* compiled = op.load_code_block();
91 switch (op.rel_type()) {
92 case RT_ENTRY_POINT: {
93 cell owner = compiled->owner;
94 if (to_boolean(owner))
95 op.store_value(parent->compute_entry_point_address(owner));
98 case RT_ENTRY_POINT_PIC: {
99 if (reset_inline_caches || !compiled->pic_p()) {
100 cell owner = parent->code_block_owner(compiled);
101 if (to_boolean(owner))
102 op.store_value(parent->compute_entry_point_pic_address(owner));
106 case RT_ENTRY_POINT_PIC_TAIL: {
107 if (reset_inline_caches || !compiled->pic_p()) {
108 cell owner = parent->code_block_owner(compiled);
109 if (to_boolean(owner))
110 op.store_value(parent->compute_entry_point_pic_tail_address(owner));
120 /* Relocate new code blocks completely; updating references to literals,
121 dlsyms, and words. For all other words in the code heap, we only need
122 to update references to other words, without worrying about literals
124 void factor_vm::update_word_references(code_block* compiled,
125 bool reset_inline_caches) {
126 if (code->uninitialized_p(compiled))
127 initialize_code_block(compiled);
128 /* update_word_references() is always applied to every block in
129 the code heap. Since it resets all call sites to point to
130 their canonical entry point (cold entry point for non-tail calls,
131 standard entry point for tail calls), it means that no PICs
132 are referenced after this is done. So instead of polluting
133 the code heap with dead PICs that will be freed on the next
134 GC, we add them to the free list immediately. */
135 else if (reset_inline_caches && compiled->pic_p())
136 code->free(compiled);
138 update_word_references_relocation_visitor visitor(this,
139 reset_inline_caches);
140 compiled->each_instruction_operand(visitor);
141 compiled->flush_icache();
145 /* Look up an external library symbol referenced by a compiled code
147 cell factor_vm::compute_dlsym_address(array* parameters,
150 cell symbol = array_nth(parameters, index);
151 cell library = array_nth(parameters, index + 1);
152 dll* d = to_boolean(library) ? untag<dll>(library) : NULL;
154 cell undef = (cell)factor::undefined_symbol;
155 undef = toc ? FUNCTION_TOC_POINTER(undef) : FUNCTION_CODE_POINTER(undef);
156 if (d != NULL && !d->handle)
159 FACTOR_ASSERT(TAG(symbol) == BYTE_ARRAY_TYPE);
160 symbol_char* name = alien_offset(symbol);
161 cell sym = ffi_dlsym_raw(d, name);
162 sym = toc ? FUNCTION_TOC_POINTER(sym) : FUNCTION_CODE_POINTER(sym);
163 return sym ? sym : undef;
166 cell factor_vm::compute_vm_address(cell arg) {
167 return (cell)this + untag_fixnum(arg);
170 cell factor_vm::lookup_external_address(relocation_type rel_type,
171 code_block *compiled,
176 return compute_dlsym_address(parameters, index, false);
178 return compiled->entry_point();
179 case RT_MEGAMORPHIC_CACHE_HITS:
180 return (cell)&dispatch_stats.megamorphic_cache_hits;
182 return compute_vm_address(array_nth(parameters, index));
183 case RT_CARDS_OFFSET:
185 case RT_DECKS_OFFSET:
189 return compute_dlsym_address(parameters, index, true);
191 case RT_INLINE_CACHE_MISS:
192 return (cell)&factor::inline_cache_miss;
194 return code->safepoint_page;
200 cell factor_vm::compute_external_address(instruction_operand op) {
201 code_block* compiled = op.compiled;
202 array* parameters = to_boolean(compiled->parameters)
203 ? untag<array>(compiled->parameters)
206 relocation_type rel_type = op.rel_type();
208 cell ext_addr = lookup_external_address(rel_type, compiled, parameters, idx);
209 if (ext_addr == (cell)-1) {
211 print_obj(ss, compiled->owner);
214 if (rel_type == RT_DLSYM || rel_type == RT_DLSYM_TOC) {
215 ss << "Bad symbol specifier in compute_external_address";
216 arg = array_nth(parameters, idx);
218 ss << "Bad rel type in compute_external_address";
221 critical_error(ss.str().c_str(), arg);
226 cell factor_vm::compute_here_address(cell arg, cell offset,
227 code_block* compiled) {
228 fixnum n = untag_fixnum(arg);
230 return compiled->entry_point() + offset + n;
231 return compiled->entry_point() - n;
234 struct initial_code_block_visitor {
239 initial_code_block_visitor(factor_vm* parent, cell literals)
240 : parent(parent), literals(literals), literal_index(0) {}
242 cell next_literal() {
243 return array_nth(untag<array>(literals), literal_index++);
246 fixnum compute_operand_value(instruction_operand op) {
247 switch (op.rel_type()) {
249 return next_literal();
251 return parent->compute_entry_point_address(next_literal());
252 case RT_ENTRY_POINT_PIC:
253 return parent->compute_entry_point_pic_address(next_literal());
254 case RT_ENTRY_POINT_PIC_TAIL:
255 return parent->compute_entry_point_pic_tail_address(next_literal());
257 return parent->compute_here_address(
258 next_literal(), op.rel_offset(), op.compiled);
260 return untag_fixnum(next_literal());
262 return parent->compute_external_address(op);
266 void operator()(instruction_operand op) {
267 op.store_value(compute_operand_value(op));
271 /* Perform all fixups on a code block */
272 void factor_vm::initialize_code_block(code_block* compiled, cell literals) {
273 initial_code_block_visitor visitor(this, literals);
274 compiled->each_instruction_operand(visitor);
275 compiled->flush_icache();
277 /* next time we do a minor GC, we have to trace this code block, since
278 the newly-installed instruction operands might point to literals in
280 code->write_barrier(compiled);
283 void factor_vm::initialize_code_block(code_block* compiled) {
284 std::map<code_block*, cell>::iterator iter =
285 code->uninitialized_blocks.find(compiled);
286 initialize_code_block(compiled, iter->second);
287 code->uninitialized_blocks.erase(iter);
290 /* Fixup labels. This is done at compile time, not image load time */
291 void factor_vm::fixup_labels(array* labels, code_block* compiled) {
292 cell size = array_capacity(labels);
294 for (cell i = 0; i < size; i += 3) {
295 relocation_class rel_class =
296 (relocation_class) untag_fixnum(array_nth(labels, i));
297 cell offset = untag_fixnum(array_nth(labels, i + 1));
298 cell target = untag_fixnum(array_nth(labels, i + 2));
300 relocation_entry new_entry(RT_HERE, rel_class, offset);
302 instruction_operand op(new_entry, compiled, 0);
303 op.store_value(target + compiled->entry_point());
308 /* Allocates memory */
309 code_block* factor_vm::allot_code_block(cell size, code_block_type type) {
310 code_block* block = code->allocator->allot(size + sizeof(code_block));
312 /* If allocation failed, do a full GC and compact the code heap.
313 A full GC that occurs as a result of the data heap filling up does not
314 trigger a compaction. This setup ensures that most GCs do not compact
315 the code heap, but if the code fills up, it probably means it will be
316 fragmented after GC anyway, so its best to compact. */
318 primitive_compact_gc();
319 block = code->allocator->allot(size + sizeof(code_block));
321 /* Insufficient room even after code GC, give up */
323 std::cout << "Code heap used: " << code->allocator->occupied_space()
325 std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
326 fatal_error("Out of memory in add-compiled-block", 0);
330 block->set_type(type);
335 /* Allocates memory */
336 code_block* factor_vm::add_code_block(code_block_type type, cell code_,
337 cell labels_, cell owner_,
338 cell relocation_, cell parameters_,
340 cell frame_size_untagged) {
341 data_root<byte_array> code(code_, this);
342 data_root<object> labels(labels_, this);
343 data_root<object> owner(owner_, this);
344 data_root<byte_array> relocation(relocation_, this);
345 data_root<array> parameters(parameters_, this);
346 data_root<array> literals(literals_, this);
348 cell code_length = array_capacity(code.untagged());
349 code_block* compiled = allot_code_block(code_length, type);
351 compiled->owner = owner.value();
353 /* slight space optimization */
354 if (relocation.type() == BYTE_ARRAY_TYPE &&
355 array_capacity(relocation.untagged()) == 0)
356 compiled->relocation = false_object;
358 compiled->relocation = relocation.value();
360 if (parameters.type() == ARRAY_TYPE &&
361 array_capacity(parameters.untagged()) == 0)
362 compiled->parameters = false_object;
364 compiled->parameters = parameters.value();
367 memcpy(compiled + 1, code.untagged() + 1, code_length);
370 if (to_boolean(labels.value()))
371 fixup_labels(labels.as<array>().untagged(), compiled);
373 compiled->set_stack_frame_size(frame_size_untagged);
375 /* Once we are ready, fill in literal and word references in this code
376 block's instruction operands. In most cases this is done right after this
377 method returns, except when compiling words with the non-optimizing
378 compiler at the beginning of bootstrap */
379 this->code->uninitialized_blocks.insert(
380 std::make_pair(compiled, literals.value()));
381 this->code->all_blocks.insert((cell)compiled);
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);
390 /* References to undefined symbols are patched up to call this function on
391 image load. It finds the symbol and library, and throws an error. */
392 void factor_vm::undefined_symbol() {
393 cell frame = ctx->callstack_top;
394 cell return_address = *(cell*)frame;
395 code_block* compiled = code->code_block_for_address(return_address);
397 /* Find the RT_DLSYM relocation nearest to the given return
399 cell symbol = false_object;
400 cell library = false_object;
402 auto find_symbol_at_address_visitor = [&](instruction_operand op) {
403 if (op.rel_type() == RT_DLSYM && op.pointer <= return_address) {
404 array* parameters = untag<array>(compiled->parameters);
405 cell index = op.index;
406 symbol = array_nth(parameters, index);
407 library = array_nth(parameters, index + 1);
410 compiled->each_instruction_operand(find_symbol_at_address_visitor);
412 if (!to_boolean(symbol))
413 critical_error("Can't find RT_DLSYM at return address", return_address);
415 general_error(ERROR_UNDEFINED_SYMBOL, symbol, library);
418 void undefined_symbol() {
419 return current_vm()->undefined_symbol();