5 static cell code_block_owner(code_block* compiled) {
6 tagged<object> owner(compiled->owner);
8 // Cold generic word call sites point to quotations that call the
9 // inline-cache-miss and inline-cache-miss-tail primitives.
10 if (owner.type() == QUOTATION_TYPE) {
11 tagged<quotation> quot(owner.as<quotation>());
12 tagged<array> elements(quot->array);
14 FACTOR_ASSERT(array_capacity(elements.untagged()) == 5);
15 FACTOR_ASSERT(array_nth(elements.untagged(), 4) ==
16 special_objects[PIC_MISS_WORD] ||
17 array_nth(elements.untagged(), 4) ==
18 special_objects[PIC_MISS_TAIL_WORD]);
20 tagged<wrapper> word_wrapper(array_nth(elements.untagged(), 0));
21 return word_wrapper->object;
23 return compiled->owner;
26 static cell compute_entry_point_address(cell obj) {
27 switch (tagged<object>(obj).type()) {
29 return untag<word>(obj)->entry_point;
31 return untag<quotation>(obj)->entry_point;
33 critical_error("Expected word or quotation", obj);
38 static cell compute_here_address(cell arg, cell offset, code_block* compiled) {
39 fixnum n = untag_fixnum(arg);
41 return compiled->entry_point() + offset + n;
42 return compiled->entry_point() - n;
45 cell code_block::owner_quot() const {
46 tagged<object> executing(owner);
47 if (type() != CODE_BLOCK_OPTIMIZED && executing->type() == WORD_TYPE)
48 executing = executing.as<word>()->def;
49 return executing.value();
52 // If the code block is an unoptimized quotation, we can calculate the
53 // scan offset. In all other cases -1 is returned.
54 // Allocates memory (quot_code_offset_to_scan)
55 cell code_block::scan(factor_vm* vm, cell addr) const {
56 if (type() != CODE_BLOCK_UNOPTIMIZED) {
57 return tag_fixnum(-1);
60 tagged<object> obj(owner);
61 if (obj.type() == WORD_TYPE)
62 obj = obj.as<word>()->def;
63 if (obj.type() != QUOTATION_TYPE)
64 return tag_fixnum(-1);
65 cell ofs = offset(addr);
66 return tag_fixnum(vm->quot_code_offset_to_scan(obj.value(), ofs));
69 cell factor_vm::compute_entry_point_pic_address(word* w, cell tagged_quot) {
70 if (!to_boolean(tagged_quot) || max_pic_size == 0)
71 return w->entry_point;
72 quotation* q = untag<quotation>(tagged_quot);
73 if (quotation_compiled_p(q))
74 return q->entry_point;
75 return w->entry_point;
78 cell factor_vm::compute_entry_point_pic_address(cell w_) {
80 return compute_entry_point_pic_address(w.untagged(), w->pic_def);
83 cell factor_vm::compute_entry_point_pic_tail_address(cell w_) {
85 return compute_entry_point_pic_address(w.untagged(), w->pic_tail_def);
88 // Relocate new code blocks completely; updating references to literals,
89 // dlsyms, and words. For all other words in the code heap, we only need
90 // to update references to other words, without worrying about literals
92 void factor_vm::update_word_references(code_block* compiled,
93 bool reset_inline_caches) {
94 if (code->uninitialized_p(compiled)) {
95 initialize_code_block(compiled);
96 // update_word_references() is always applied to every block in
97 // the code heap. Since it resets all call sites to point to
98 // their canonical entry point (cold entry point for non-tail calls,
99 // standard entry point for tail calls), it means that no PICs
100 // are referenced after this is done. So instead of polluting
101 // the code heap with dead PICs that will be freed on the next
102 // GC, we add them to the free list immediately.
103 } else if (reset_inline_caches && compiled->pic_p()) {
104 code->free(compiled);
106 auto visit_func = [&](instruction_operand op) {
108 switch (op.rel.type()) {
109 case RT_ENTRY_POINT: {
110 code_block* dest = op.load_code_block();
111 cell owner = dest->owner;
112 if (to_boolean(owner))
113 op.store_value(compute_entry_point_address(owner));
116 case RT_ENTRY_POINT_PIC: {
117 code_block* dest = op.load_code_block();
118 if (reset_inline_caches || !dest->pic_p()) {
119 cell owner = code_block_owner(dest);
120 if (to_boolean(owner))
121 op.store_value(compute_entry_point_pic_address(owner));
125 case RT_ENTRY_POINT_PIC_TAIL: {
126 code_block* dest = op.load_code_block();
127 if (reset_inline_caches || !dest->pic_p()) {
128 cell owner = code_block_owner(dest);
129 if (to_boolean(owner))
130 op.store_value(compute_entry_point_pic_tail_address(owner));
138 compiled->each_instruction_operand(visit_func);
139 compiled->flush_icache();
143 // Look up an external library symbol referenced by a compiled code block
144 cell factor_vm::compute_dlsym_address(array* parameters,
147 cell symbol = array_nth(parameters, index);
148 cell library = array_nth(parameters, index + 1);
149 dll* d = to_boolean(library) ? untag<dll>(library) : NULL;
151 cell undef = (cell)factor::undefined_symbol;
152 undef = toc ? FUNCTION_TOC_POINTER(undef) : FUNCTION_CODE_POINTER(undef);
153 if (d != NULL && !d->handle)
156 FACTOR_ASSERT(TAG(symbol) == BYTE_ARRAY_TYPE);
157 symbol_char* name = alien_offset(symbol);
158 cell sym = ffi_dlsym_raw(d, name);
159 sym = toc ? FUNCTION_TOC_POINTER(sym) : FUNCTION_CODE_POINTER(sym);
160 return sym ? sym : undef;
163 cell factor_vm::lookup_external_address(relocation_type rel_type,
164 code_block *compiled,
169 return compute_dlsym_address(parameters, index, false);
171 return compiled->entry_point();
172 case RT_MEGAMORPHIC_CACHE_HITS:
173 return (cell)&dispatch_stats.megamorphic_cache_hits;
175 return (cell)this + untag_fixnum(array_nth(parameters, index));
176 case RT_CARDS_OFFSET:
178 case RT_DECKS_OFFSET:
182 return compute_dlsym_address(parameters, index, true);
184 case RT_INLINE_CACHE_MISS:
185 return (cell)&factor::inline_cache_miss;
187 return code->safepoint_page;
193 cell factor_vm::compute_external_address(instruction_operand op) {
194 code_block* compiled = op.compiled;
195 array* parameters = to_boolean(compiled->parameters)
196 ? untag<array>(compiled->parameters)
199 relocation_type rel_type = op.rel.type();
201 cell ext_addr = lookup_external_address(rel_type, compiled, parameters, idx);
202 if (ext_addr == (cell)-1) {
204 print_obj(ss, compiled->owner);
207 if (rel_type == RT_DLSYM || rel_type == RT_DLSYM_TOC) {
208 ss << "Bad symbol specifier in compute_external_address";
209 arg = array_nth(parameters, idx);
211 ss << "Bad rel type in compute_external_address";
214 critical_error(ss.str().c_str(), arg);
219 struct initial_code_block_visitor {
224 initial_code_block_visitor(factor_vm* parent, cell literals)
225 : parent(parent), literals(literals), literal_index(0) {}
227 cell next_literal() {
228 return array_nth(untag<array>(literals), literal_index++);
231 fixnum compute_operand_value(instruction_operand op) {
232 switch (op.rel.type()) {
234 return next_literal();
236 return compute_entry_point_address(next_literal());
237 case RT_ENTRY_POINT_PIC:
238 return parent->compute_entry_point_pic_address(next_literal());
239 case RT_ENTRY_POINT_PIC_TAIL:
240 return parent->compute_entry_point_pic_tail_address(next_literal());
242 return compute_here_address(
243 next_literal(), op.rel.offset(), op.compiled);
245 return untag_fixnum(next_literal());
247 return parent->compute_external_address(op);
251 void operator()(instruction_operand op) {
252 op.store_value(compute_operand_value(op));
256 // Perform all fixups on a code block
257 void factor_vm::initialize_code_block(code_block* compiled, cell literals) {
258 initial_code_block_visitor visitor(this, literals);
259 compiled->each_instruction_operand(visitor);
260 compiled->flush_icache();
262 // next time we do a minor GC, we have to trace this code block, since
263 // the newly-installed instruction operands might point to literals in
265 code->write_barrier(compiled);
268 void factor_vm::initialize_code_block(code_block* compiled) {
269 std::map<code_block*, cell>::iterator iter =
270 code->uninitialized_blocks.find(compiled);
271 initialize_code_block(compiled, iter->second);
272 code->uninitialized_blocks.erase(iter);
275 // Fixup labels. This is done at compile time, not image load time
276 void factor_vm::fixup_labels(array* labels, code_block* compiled) {
277 cell size = array_capacity(labels);
279 for (cell i = 0; i < size; i += 3) {
280 relocation_class rel_class =
281 (relocation_class) untag_fixnum(array_nth(labels, i));
282 cell offset = untag_fixnum(array_nth(labels, i + 1));
283 cell target = untag_fixnum(array_nth(labels, i + 2));
285 relocation_entry new_entry(RT_HERE, rel_class, offset);
287 instruction_operand op(new_entry, compiled, 0);
288 op.store_value(target + compiled->entry_point());
294 code_block* factor_vm::add_code_block(code_block_type type, cell code_,
295 cell labels_, cell owner_,
296 cell relocation_, cell parameters_,
298 cell frame_size_untagged) {
299 data_root<byte_array> code(code_, this);
300 data_root<object> labels(labels_, this);
301 data_root<object> owner(owner_, this);
302 data_root<byte_array> relocation(relocation_, this);
303 data_root<array> parameters(parameters_, this);
304 data_root<array> literals(literals_, this);
306 cell code_length = array_capacity(code.untagged());
307 code_block* compiled = allot_code_block(code_length, type);
309 compiled->owner = owner.value();
311 // slight space optimization
312 if (relocation.type() == BYTE_ARRAY_TYPE &&
313 array_capacity(relocation.untagged()) == 0)
314 compiled->relocation = false_object;
316 compiled->relocation = relocation.value();
318 if (parameters.type() == ARRAY_TYPE &&
319 array_capacity(parameters.untagged()) == 0)
320 compiled->parameters = false_object;
322 compiled->parameters = parameters.value();
325 memcpy(compiled + 1, code.untagged() + 1, code_length);
328 if (to_boolean(labels.value()))
329 fixup_labels(labels.as<array>().untagged(), compiled);
331 compiled->set_stack_frame_size(frame_size_untagged);
333 // Once we are ready, fill in literal and word references in this code
334 // block's instruction operands. In most cases this is done right after this
335 // method returns, except when compiling words with the non-optimizing
336 // compiler at the beginning of bootstrap
337 this->code->uninitialized_blocks.insert(
338 std::make_pair(compiled, literals.value()));
339 this->code->all_blocks.insert((cell)compiled);
344 // References to undefined symbols are patched up to call this function on
345 // image load. It finds the symbol and library, and throws an error.
346 void factor_vm::undefined_symbol() {
347 cell frame = ctx->callstack_top;
348 cell return_address = *(cell*)frame;
349 code_block* compiled = code->code_block_for_address(return_address);
351 // Find the RT_DLSYM relocation nearest to the given return address.
352 cell symbol = false_object;
353 cell library = false_object;
355 auto find_symbol_at_address_visitor = [&](instruction_operand op) {
356 if (op.rel.type() == RT_DLSYM && op.pointer <= return_address) {
357 array* parameters = untag<array>(compiled->parameters);
358 cell index = op.index;
359 symbol = array_nth(parameters, index);
360 library = array_nth(parameters, index + 1);
363 compiled->each_instruction_operand(find_symbol_at_address_visitor);
365 if (!to_boolean(symbol))
366 critical_error("Can't find RT_DLSYM at return address", return_address);
368 general_error(ERROR_UNDEFINED_SYMBOL, symbol, library);
371 void undefined_symbol() {
372 return current_vm()->undefined_symbol();